Applicative是Monoidal Functor:
mappend :: f -> f -> f
$ :: (a -> b) -> a -> b
<*> :: f(a -> b) -> f a -> f b
但是我没有在应用类型类的定义中看到有关Monoid的任何参考,你能告诉我为什么吗?
定义:
class Functor f => Applicative (f :: * -> *) where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
GHC.Base.liftA2 :: (a -> b -> c) -> f a -> f b -> f c
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
{-# MINIMAL pure, ((<*>) | liftA2) #-}
此定义中没有提到结构Monoid,但是当你这样做时
> ("ab",(+1)) <*> ("cd", 5)
>("abcd", 6)
你可以清楚地看到使用结构Monoid&#34;(,)String&#34;在实现Applicative的这个实例时。
另一个显示&#34;结构Monoid&#34;使用:
Prelude Data.Monoid> (2::Integer,(+1)) <*> (1::Integer,5)
<interactive>:35:1: error:
• Could not deduce (Monoid Integer) arising from a use of ‘<*>’
from the context: Num b
bound by the inferred type of it :: Num b => (Integer, b)
at <interactive>:35:1-36
• In the expression: (2 :: Integer, (+ 1)) <*> (1 :: Integer, 5)
In an equation for ‘it’:
it = (2 :: Integer, (+ 1)) <*> (1 :: Integer, 5)
答案 0 :(得分:11)
“monoidal functor”所指的幺半群不是Monoid
幺半群,即一个数值级的幺半群。它取而代之的是类型级monoid 。即,镗孔产品monoid
type Mempty = ()
type a <> b = (a,b)
(您可能会注意到这并不是严格意义上的幺半群;只有当您将((a,b),c)
和(a,(b,c))
视为同一类型时才会这样。它们确实足够同构。)
要了解这与Applicative
有何关系,请参阅。 monoidal仿函数,我们需要用其他术语来编写类。
class Functor f => Monoidal f where
pureUnit :: f Mempty
fzip :: f a -> f b -> f (a<>b)
-- an even more “general nonsense”, equivalent formulation is
-- upure :: Mempty -> f Mempty
-- fzipt :: (f a<>f b) -> f (a<>b)
-- i.e. the functor maps a monoid to a monoid (in this case the same monoid).
-- That's really the mathematical idea behind this all.
IOW
class Functor f => Monoidal f where
pureUnit :: f ()
fzip :: f a -> f b -> f (a,b)
根据Applicative
定义标准Monoidal
类的通用实例是一项简单的练习,反之亦然。
关于("ab",(+1)) <*> ("cd", 5)
:这与Applicative
一般没有多大关系,但仅与作者应用具体相关。实例是
instance Monoid a => Monoidal ((,) a) where
pureUnit = (mempty, ())
fzip (p,a) (q,b) = (p<>q, (a,b))
答案 1 :(得分:10)
也许你正在寻找的幺半群就是这个。
newtype AppM f m = AppM (f m) deriving Show
instance (Applicative f, Monoid m) => Monoid (AppM f m) where
mempty = AppM (pure mempty)
mappend (AppM fx) (AppM fy) = AppM (pure mappend <*> fx <*> fy)
作为评论,在下面观察,它可以在名为Ap
的{{3}}库中找到。它是Applicative
的基础,所以让我们打开它。
特别注意,因为()
只是Monoid
,AppM f ()
也是Monoid
。这就是潜伏在Applicative f
背后的幺半群。
我们本可以坚持Monoid (f ())
作为Applicative
的超类,但这会对王室产生污染。
> mappend (AppM [(),()]) (AppM [(),(),()])
AppM [(),(),(),(),(),()]
Applicative []
下面的幺半群是自然数的乘法,而列表的“明显”幺半群结构是连接,专门用于自然数的加法
数学警告。依赖类型警告。假Haskell警告。
了解正在发生的事情的一种方法是在依赖类型的雅培,Altenkirch和Ghani意义上考虑那些碰巧是容器的Applicative。我们很快就会在Haskell中拥有这些。我只是假装未来已经到来。
data (<|) (s :: *)(p :: s -> *) (x :: *) where
(:<|:) :: pi (a :: s) -> (p a -> x) -> (s <| p) x
数据结构(s <| p)
的特点是
s
告诉您容器的外观。p
告诉您指定的形状,您可以在其中放置数据。上述类型表示,为这样的结构提供数据是选择一个形状,然后用数据填充所有位置。
[]
的容器演示文稿是Nat <| Fin
其中
data Nat = Z | S Nat
data Fin (n :: Nat) where
FZ :: Fin (S n)
FS :: Fin n -> Fin (S n)
以便Fin n
具有完全n
个值。也就是说,列表的形状是 length ,它会告诉您填充列表需要多少元素。
您可以通过Functor f
找到Haskell f ()
的形状。通过使数据变得微不足道,这些位置并不重要。在Haskell中一般地构建GADT位置要困难得多。
Parametricity告诉我们
中容器之间的多态函数forall x. (s <| p) x -> (s' <| p') x
必须由
提供f :: s -> s'
g :: pi (a :: s) -> p' (f a) -> p a
映射(对于给定的输入形状)输出位置返回到输出元素将来自的输入位置。
morph f g (a :<|: d) = f a :<|: (d . g a)
(偷偷地说,我们这些接受过基本汉考克训练的人也会想到&#34;形状&#34; as&#34;命令&#34;和#34;位置&#34; as&#34;有效的回答&#34;。容器之间的态度恰好是&#34;设备驱动程序&#34;。但我离题了。)
按照类似的思路思考,制作容器Applicative
需要做些什么?首先,
pure :: x -> (s <| p) x
等同于
pure :: (() <| Const ()) x -> (s <| p) x
必须由
提供f :: () -> s -- a constant in s
g :: pi (a :: ()) -> p (f ()) -> Const () a -- trivial
某些
的f = const neutral
neutral :: s
现在,
怎么样?(<*>) :: (s <| p) (x -> y) -> (s <| p) x -> (s <| p) y
?同样,参数化告诉我们两件事。首先,计算输出形状的唯一有用数据是两个输入形状。我们必须有一个功能
outShape :: s -> s -> s
其次,我们用y
填充输出位置的唯一方法是从第一个输入中选择一个位置以找到`x - &gt;中的函数。 ý&#39;然后在第二个输入中的位置以获得其参数。
inPos :: pi (a :: s)(b :: s) -> p (outShape a b) -> (p a, p b)
也就是说,我们总是可以识别确定输出位置输出的输入位置对。
适用法则告诉我们neutral
和outShape
必须遵守幺半群定律,而且,我们可以按如下方式提升幺半群
mappend (a :<|: f) (b :<|: g) = outShape a b :<|: \ z ->
let (x, y) = inPos a b z
in mappend (f x) (g y)
此处还有更多要说的内容,但为此,我需要对容器上的两个操作进行对比。
<强>组合物强>
(s <| p) . (s' <| p') = ((s <| p) s') <| \ (a :<|: f) -> Sigma (p a) (p' . f)
其中Sigma
是依赖对的类型
data Sigma (p :: *)(q :: p -> *) where
Pair :: pi (a :: p) -> q a -> Sigma p q
这究竟是什么意思?
或者,在汉考克
或者,更加公然
join
的{{1}}会使作文变平。潜伏在它背后不仅仅是形状上的幺半群,而是集成运算符。也就是说,
Monad
需要
join :: ((s <| p) . (s <| p)) x -> (s <| p) x
您的免费monad会为您提供策略树,您可以使用一个命令的结果来选择策略的其余部分。好像你在20世纪70年代的电传打字机上进行互动一样。
...同时
<强>张量强>
两个集装箱的张量(也是汉考克)是由
给出的integrate :: (s <| p) s -> s
那是
或
或
(s <| p) >< (s' <| p') = (s, s') <| \ (a, b) -> (p a, p' b)
是矩形矩阵的类型:'内部'列表必须全部具有相同的长度后者是一个线索,为什么[] >< []
很难在Haskell中获取,但在依赖类型的设置中很容易。
与组合一样,张量是一个以身份函子作为其中性元素的幺半群。如果我们用张量替换><
下面的构图,我们得到了什么?
Monad
但是pure :: Id x -> (s <| p) x
mystery :: ((s <| p) >< (s <| p)) x -> (s <| p) x
可以做什么?这不是一个谜,因为我们知道在容器之间制作多态函数是一种相当严格的方法。必须有
mystery
这些正是我们之前所说的f :: (s, s) -> s
g :: pi ((a, b) :: (s, s)) -> p (f (a, b)) -> (p a, p b)
所确定的。
<*>
是由张量生成的有效编程的概念,其中Applicative
由组合生成。您没有/需要等待外部响应来选择内部命令这一事实是Monad
程序更容易并行化的原因。
将Applicative
视为矩形矩阵告诉我们为什么列表的[] >< []
建立在乘法之上。
免费的applicative functor是带有旋钮的免费monoid。对于容器,
<*>
,其中
Free (s <| p) = [s] <| All p
所以&#34;命令&#34;是一个很大的命令列表,就像一副穿孔卡片。在选择卡片组之前,您无法看到任何输出。 &#34;响应&#34;是你的lineprinter输出。这是20世纪60年代。
所以你去吧。 All p [] = ()
All p (x : xs) = (p x, All p xs)
的本质,张量不是构成,需要一个潜在的幺半群,以及与幺半群相容的元素的重组。
答案 2 :(得分:1)
我想用在Monoid
s中找到的Applicative
的更多示例来补充Conor McBride(pigworker)的instructive answer。
It has been observed某些函子的Applicative
实例类似于相应的Monoid
实例;
例如,我们有以下类推:
Applicative → Monoid
---------------------
List → Product
Maybe → All
Either a → First a
State s → Endo s
根据Conor的评论,我们可以理解为什么为什么有这些对应关系。 我们使用以下观察结果:
Applicative
下,Monoid
容器的形状形成<*>
。F
的形状由F 1
给出(其中1
表示单位()
)。对于上面列出的每个Applicative
仿函数,我们通过使用unit元素实例化仿函数来计算其形状。
我们明白了...
List
的形状为Nat
:
List a = μ r . 1 + a × r
List 1 = μ r . 1 + 1 × r
≅ μ r . 1 + r
≅ Nat
Maybe
的形状为Bool
:
Maybe a = 1 + a
Maybe 1 = 1 + 1
≅ Bool
Either
的形状为Maybe
:
Either a b = a + b
Either a 1 = a + 1
≅ Maybe a
State
的形状为Endo
:
State s a = (a × s) ^ s
State s 1 = (1 × s) ^ s
≅ s ^ s
≅ Endo s
形状的类型与开头列出的Monoid
下的类型完全匹配。
有一件事仍然让我感到困惑:其中一些类型允许多个Monoid
实例( eg ,Bool
可以被做成Monoid
的{{1}}或All
),但我不确定为什么我们要获得其中一个实例,而不是另一个。我的猜测是,这与适用法律以及它们如何与容器的其他组件(容器的位置)相互作用有关。