J C*_*per 101 haskell operators
你如何在Applicative类型类中发音这些函数:
(<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
Run Code Online (Sandbox Code Playgroud)
(也就是说,如果他们不是运营商,他们会被称为什么?)
作为旁注,如果你可以重命名pure
为对非数学家更友好的东西,你会怎么称呼它?
C. *_*ann 238
对不起,我真的不懂我的数学,所以我很好奇如何在Applicative类型类中发音
我想,知道你的数学与否,在很大程度上与此无关.正如你可能知道的那样,Haskell从抽象数学的各个领域借用了一些术语,最着名的是类别理论,从那里我们得到了仿函数和monad.在Haskell中使用这些术语在某种程度上与正式的数学定义有所不同,但它们通常足够接近,无论如何都是良好的描述性术语.
该Applicative
类型的课坐在某处之间Functor
和Monad
,所以人们期望它有一个类似的数学基础.该Control.Applicative
模块的文档以:
该模块描述了仿函数和monad之间的结构:它提供纯表达式和排序,但没有绑定.(从技术上讲,它是一个强大的松散幺半体仿函数.)
嗯.
class (Functor f) => StrongLaxMonoidalFunctor f where
. . .
Run Code Online (Sandbox Code Playgroud)
Monad
我认为不像那些吸引人.
所有这一切基本归结为Applicative
与数学上特别有趣的任何概念不对应,因此没有现成的术语可以捕捉它在Haskell中的使用方式.所以,暂时把数学放在一边.
如果我们想知道该怎么称,(<*>)
它可能有助于了解它的基本含义.
那么什么是有Applicative
,反正,为什么做,我们称呼它?
什么Applicative
在实践中达是解除的方式任意功能集成到一个Functor
.考虑Maybe
(可以说是最简单的非平凡Functor
)和Bool
(最简单的非平凡数据类型)的组合.
maybeNot :: Maybe Bool -> Maybe Bool
maybeNot = fmap not
Run Code Online (Sandbox Code Playgroud)
该功能fmap
让我们not
从工作Bool
转向工作Maybe Bool
.但是,如果我们想举起(&&)
怎么办?
maybeAnd' :: Maybe Bool -> Maybe (Bool -> Bool)
maybeAnd' = fmap (&&)
Run Code Online (Sandbox Code Playgroud)
嗯,那不是我们想要的!事实上,它几乎没用.我们可以试着聪明和潜入另一Bool
成Maybe
通过背...
maybeAnd'' :: Maybe Bool -> Bool -> Maybe Bool
maybeAnd'' x y = fmap ($ y) (fmap (&&) x)
Run Code Online (Sandbox Code Playgroud)
......但这不好.首先,这是错误的.另一件事,它很难看.我们可以继续尝试,但事实证明,没有办法解除多个参数的函数来处理任意问题Functor
.烦!
另一方面,如果我们使用Maybe
的Monad
实例,我们可以轻松地做到:
maybeAnd :: Maybe Bool -> Maybe Bool -> Maybe Bool
maybeAnd x y = do x' <- x
y' <- y
return (x' && y')
Run Code Online (Sandbox Code Playgroud)
现在,翻译一个简单的函数是很麻烦的 - 这就是为什么Control.Monad
提供一个自动执行它的功能的原因liftM2
.名称中的2指的是它适用于两个参数的函数; 3,4和5参数函数存在类似的函数.这些函数更好,但并不完美,指定参数的数量是丑陋和笨拙的.
这将我们带到介绍Applicative类型的论文.其中,作者基本上提出了两点意见:
Functor
是非常自然的事情Monad
正常功能应用程序是通过简单并置的术语编写的,因此为了使"提升应用程序"尽可能简单和自然,本文介绍了中缀操作符代表应用程序,提升到Functor
类型类,以提供所需的内容. .
所有这些都将我们带到了以下几点:(<*>)
简单地表示函数应用程序 - 所以为什么发音它的方式与空格"并置运算符"不同?
但是如果这不是很令人满意,我们可以观察到该Control.Monad
模块还提供了一个为monad做同样事情的函数:
ap :: (Monad m) => m (a -> b) -> m a -> m b
Run Code Online (Sandbox Code Playgroud)
其中ap
,当然,短期为"适用".由于任何Monad
可以Applicative
,并且ap
只需要后者中存在的特征子集,我们可以说如果(<*>)
不是运算符,则应该调用它ap
.
我们也可以从另一个方向处理事情.在Functor
提升操作被称为fmap
,因为它是一个泛化map
的列表操作.列表上的哪种功能会起作用(<*>)
?ap
当然,列表上有什么东西,但这本身并不是特别有用.
事实上,列表可能有更自然的解释.当您查看以下类型签名时会想到什么?
listApply :: [a -> b] -> [a] -> [b]
Run Code Online (Sandbox Code Playgroud)
对于将列表并行排列的想法非常诱人,将第一个中的每个函数应用到第二个中的相应元素.不幸的是,对于我们的老朋友来说Monad
,如果列表的长度不同,这个简单的操作就违反了monad法则.但它很好Applicative
,在这种情况下(<*>)
成为一种将通用版本串联起来的方式,所以也许我们可以设想调用它?zipWith
fzipWith
这种拉链式的想法实际上给我们带来了完整 回想一下之前的数学问题,关于幺半群算子?顾名思义,这些是一种结合幺半群和仿函数结构的方法,这两种方法都是熟悉的Haskell类型:
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Monoid a where
mempty :: a
mappend :: a -> a -> a
Run Code Online (Sandbox Code Playgroud)
如果你把它们放在一个盒子里并且摇晃一下,它们会是什么样子?从Functor
我们将保持结构的想法独立于其类型参数,并从Monoid
我们将保持功能的整体形式:
class (Functor f) => MonoidalFunctor f where
mfEmpty :: f ?
mfAppend :: f ? -> f ? -> f ?
Run Code Online (Sandbox Code Playgroud)
我们不想假设有一种方法来创建一个真正的"空" Functor
,我们不能想出一个任意类型的值,所以我们将修复mfEmpty
as 的类型f ()
.
我们也不想强制mfAppend
需要一致的类型参数,所以现在我们有:
class (Functor f) => MonoidalFunctor f where
mfEmpty :: f ()
mfAppend :: f a -> f b -> f ?
Run Code Online (Sandbox Code Playgroud)
结果类型是mfAppend
什么?我们有两种我们一无所知的任意类型,所以我们没有很多选择.最明智的做法是保持两者:
class (Functor f) => MonoidalFunctor f where
mfEmpty :: f ()
mfAppend :: f a -> f b -> f (a, b)
Run Code Online (Sandbox Code Playgroud)
此时mfAppend
显然是zip
on list 的通用版本,我们可以Applicative
轻松地重建:
mfPure x = fmap (\() -> x) mfEmpty
mfApply f x = fmap (\(f, x) -> f x) (mfAppend f x)
Run Code Online (Sandbox Code Playgroud)
这也向我们展示了pure
与a的identity元素相关的信息Monoid
,因此它的其他好名称可能是任何暗示单位值,空操作等的东西.
这很冗长,总结如下:
(<*>)
只是一个修改过的函数应用程序,因此您可以将其读作"ap"或"apply",或者完全按照正常函数应用程序的方式将其删除.(<*>)
也粗略地概括zipWith
了列表,所以你可以把它读作"zip functors with",类似于阅读fmap
"map with functor with".第一个更接近Applicative
类型类的意图- 顾名思义 - 这就是我推荐的.
事实上,我鼓励所有解除应用程序运营商的自由使用和非发音:
(<$>)
,将单参数函数提升为 Functor
(<*>)
,通过一个链接一个多参数函数 Applicative
(=<<)
,它绑定一个进入Monad
现有计算的函数从本质上讲,这三个都只是常规的功能应用,加了一点点.
BMe*_*eph 21
由于我没有改进CA McCann技术答案的野心,我将解决更为蓬松的问题:
如果你可以重命名
pure
为像我这样的podunks更友好的东西,你会怎么称呼它?
作为一种替代方案,特别是因为对于版本的持续焦虑和背叛填充没有结束Monad
,称为" return
",我提出了另一个名称,这表明它的功能可以满足最迫切需要的程序员......最好的功能......好吧,希望每个人都可以抱怨:inject
.
拿一个值."注入"成的Functor
,Applicative
,Monad
,或什么都有,你.我投票支持" inject
",我批准了这条消息.
归档时间: |
|
查看次数: |
16411 次 |
最近记录: |