Pure 用于將普通函式轉換為Applicative容器中的函式。有了這個,任何多引數操作都可以在Applicative. 在這種情況下,pure 不希望成為a -> f a型別,而只是希望成為(a -> b) -> f (a -> b)型別。但型別pure是a -> f a. 為什么正常值可以轉換為Applicative?pure除了轉換功能之外,還有更多用途嗎?
uj5u.com熱心網友回復:
您可以pure :: a -> f a根據lift :: (a -> b) -> f (a -> b)和定義<*>:
pure x = lift (const x) <*> lift (const ())
所以這兩種方式都是等價的,而且通常寫起來更簡單pure。
(這是Iceland_jack對設計原因的出色總結的補充。)
uj5u.com熱心網友回復:
我沒有發現Applicative應用提升函式(即(<*>))的界面是一個很好的直覺。由于各種原因,函式的概念化更加復雜。
我更喜歡將Applicative其視為提升n元函式
liftA0 :: Applicative f => (a) -> (f a)
liftA :: Functor f => (a -> b) -> (f a -> f b)
liftA2 :: Applicative f => (a -> b -> c) -> (f a -> f b -> f c)
liftA3 :: Applicative f => (a -> b -> c -> d) -> (f a -> f b -> f c -> f d)
哪里liftA0 = pure和liftA已經存在fmap定義為Applicative。
問題是 0-ary 和 1-ary 提升
liftA0 @f @a :: Applicative f => a -> f a
liftA @f @a @b :: Applicative f => (a -> b) -> (f a -> f b)
a -> b如果我們以函式型別實體化,則兩者都可以采用函式liftA0 = pure:
liftA0 @f @(a->b) :: Applicative f => (a -> b) -> f (a->b)
liftA @f @a @b :: Applicative f => (a -> b) -> (f a -> f b)
所以pure @f @(a->b)已經有那種型別了。
并且pure有很多目的,理論上在 Haskell 中被證明是實用的,它是單位 ifApplicative被視為Monoid自然變換類別中的 a ,具有 (計算概念作為 Monoids )Day
type Mempty :: Type -> Type
type Mempty = Identity
type Mappend :: (Type -> Type) -> (Type -> Type) -> (Type -> Type)
type Mappend = Day
mempty :: Applicative f => Mempty ~> f
mempty (Identity a) = pure a
mappend :: Mappend f f ~> f
mappend (LiftA2 (·) as bs) = liftA2 (·) as bs
我剛剛發布了一個使用Applicative同態的庫,這是尊重應用結構的多型函式。它為這種結構定義了一個型別類
type Idiom :: k -> (Type -> Type) -> (Type -> Type) -> Constraint
class (Applicative f, Applicative g) => Idiom tag f g where
idiom :: f ~> g
其中pure是初始應用態射。
-- https://chrisdone.com/posts/haskell-constraint-trick/
instance (Identity ~ id, Applicative f) => Idiom Initial id f where
idiom :: Identity ~> f
idiom (Identity a) = pure a
pure然后經常使用,作為計算的單位。Traversable它是Haskell 成功案例之一的驅動力
instance Traversable [] where
traverse :: Applicative f => (a -> f b) -> ([a] -> f [b])
traverse f [] = pure []
traverse f (x:xs) = ...
我們之所以需要pure,是因為我們唯一產生Applicative-action 的引數是,f x但是我們沒有一個空串列x :: a來提供它。因此,我們需要 0 元提升。
uj5u.com熱心網友回復:
有時值得從相反的方向提出問題。如果型別是,你會得到pure什么(a -> b) -> f (a -> b)?
作為有人打電話pure,這嚴格來說是降級。如前所述,(a -> b) -> f (a -> b)是pure已經的當前型別的實體化。所以在跟注方面,你只會失去選擇。
但是,實施方面是雙重的。型別越具體,實作的選項就越多。要求引數是一個函式意味著實作可以利用它來做特定于函式的事情。就像...呼叫它。這是您在 Haskell 中使用函式的唯一特殊之處。所以要呼叫它,你只需要為它提供一個a呼叫者pure可以選擇的某種型別的值。你可以得到其中之一……呃……你不能得到其中之一。唯一的選擇是使用undefined或其他一些具有普遍量化型別的底部值。你會怎樣做?pure f = let x = f undefined in ...? 這對實作 pure 有何幫助?
回到最初的問題:如果型別是 ,你會得到pure什么(a -> b) -> f (a -> b)?作為呼叫者,它嚴格來說沒那么有用。作為實施者,它提供了額外的能力,但這種額外的能力并不能幫助您做任何有用的事情。更具體的型別的好處在哪里?
uj5u.com熱心網友回復:
pure是的,除了轉換函式之外,還有更多的目的。do塊以呼叫結束是很常見的pure。通過將它的使用與<|>.
此外,它與潛在的范疇理論很好地吻合;但我真的不認為這是一個激勵原因。相反,它首先是有用的,然后被發現與先前已知的范疇論概念相吻合。(實際上,從歷史上看,我認為它是“定義有用的東西;意識到它是 monad 的概念;發現應用函子的相關概念;意識到它們是有用的。所以它實際上是“有用第一”和“理論第一”的混合“。但我永遠不會為它的存在辯護,因為它在理論上就在那里——只是因為這個理論很有洞察力而感到興奮。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/459673.html
