Enr*_*lis 6 haskell applicative
抛开这个问题。直觉上,我已经理解了sequenceA该用例中的作用,但不知道它是如何/为什么这样工作的。
所以这一切都归结为这个问题:sequenceA在以下情况下如何工作?
> sequenceA [("a",1),("b",2),("c",3)]
("abc",[1,2,3])
Run Code Online (Sandbox Code Playgroud)
我看到
sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
Run Code Online (Sandbox Code Playgroud)
所以在上面的用例中Traversableis[]和Applicative,因为(,)是一个二进制类型构造函数, is (,) a,这意味着这对被视为其snd字段上的应用函子。这与最终在snd结果中的列表结合在一起。所以我们从一个对的列表到第二个字段中有一个列表的对。
但是"abc"从哪里来?我的意思是,我知道这fst是所有对的串联,但我不知道它是通过++还是通过sconcat的列表fst。sequenceA的签名中似乎没有任何内容可以强制使对中的fsts 可以组合在一起。
仍然必须在某处使用该假设。确实,以下失败
sequenceA [('a',1),('b',2),('c',3)]
Run Code Online (Sandbox Code Playgroud)
它使用mappend. Applicative它使用的实例如下所示:
instance Monoid a => Applicative ((,) a) where
pure x = (mempty, x)
(af, f) <*> (ax, x) = (mappend af ax, f x)
Run Code Online (Sandbox Code Playgroud)
在 Haskell 中,一个类型的类型类实例可以“有条件”地存在于该类型的某些部分的其他类型类实例中。并非该表单的所有类型构造函数((,) a)都是 的实例Applicative,而只有该a类型具有Monoid实例的那些。
这些必需的约束出现在=>实例的 Haddocks 之前,如下所示:
Monoid a => Applicative ((,) a)
Run Code Online (Sandbox Code Playgroud)
为什么Monoid需要实例?首先,purefor((,) a)需要a凭空实现一个值以放入元组的第一个元素。mempty因为类型a可以完成工作。
可以有几层深的所需约束链。例如,为什么下面的工作?
ghci> import Datta.Function ((&)) -- flipped application
ghci> [(id :: String -> String, 2 :: Int), (\x -> x ++ x, 1)] & sequenceA & fst $ "foo"
"foofoofoo"
Run Code Online (Sandbox Code Playgroud)
这里的第一个组件是一个函数。和以前一样,它必须有一个Monoid实例sequenceA才能工作。但是什么时候是a -> ba类型Monoid呢?查看黑线鳕,我们发现:
Monoid b => Monoid (a -> b)
Run Code Online (Sandbox Code Playgroud)
也就是说,Monoid当返回类型(此处String)为 a时,函数为s Monoid。
实际上,还有另一个 Monoid可以通过Endonewtype使用的函数实例。使用 newtypes 来选择用于给定操作的实例是很常见的,尽管它需要一些包装和解包。