应用于Haskell中的元组和列表的不同行为

时间:2015-11-22 07:58:04

标签: haskell applicative

例如,

-- Num a => ([Char], a -> a) <*> ([Char], a)
> ("hello ",(*6)) <*> ("world",7)
("hello world",42)

-- Num a => [a -> a] <*> [a]
> [(*7),(*6)] <*> [6,7]
[42,49,36,42]

-- Num a => [[Char], a -> a] <*> [[Char], a]
> ["hello ",(*6)] <*> ["world",7]
<interactive>:17:2:
    Couldn't match expected type ‘[Char] -> [Char]’
                with actual type ‘[Char]’
    In the expression: "hello "
    In the first argument of ‘(<*>)’, namely ‘["hello ", (* 6)]’
    In the expression: ["hello ", (* 6)] <*> ["world", 7]

对于三个示例,<*>显示了不同的行为。怎么了?为什么在第三种情况下,它需要[Char] -> [Char]而不是[Char],就像第一种情况一样。更重要的是,即使元组中只有[Char]<*>也将它们组合在一起。

2 个答案:

答案 0 :(得分:4)

不同之处在于列表是同类,而元组则不是:列表只包含相同类型的元素,而元组则不包含。

即使没有看应用程序,仿函数已经显示出主要区别:

fmap succ [1,2,3]  ==> [2,3,4]
fmap succ ("a", 4) ==> ???

认为fmapsucc应用于"a"是不合逻辑的。会发生什么是只有第二个组件受到影响:

fmap succ ("a", 4) ==> ("a", 5)

确实,看看实例:

instance Functor [] where ...
instance Functor ((,) a) where ...

请注意a类型。在列表实例中,[]只接受一个类型参数,并且该类型受fmap影响。在(,)中,我们有两个类型参数:一个是固定的(到a),在应用fmap时不会改变 - 只有第二个参数。< / p>

请注意,当两个类型参数都被强制相同时,理论上可以允许Functor (,)的实例。例如,

instance Functor (\b -> (b,b)) where ...

但是Haskell不允许这样做。如果需要,需要一个newtype包装器:

newtype P b = P (b,b)
instance Functor P where
   fmap f (P (x,y)) = P (f x, f y)

答案 1 :(得分:1)

Applicative是满足applicative lawspure<*>的数据类型和定义的任意组合:

    [identity] pure id <*> v = v
 [composition] pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
[homomorphism] pure f <*> pure x = pure (f x)
 [interchange] u <*> pure y = pure ($ y) <*> u

这些法律确保<*>的行为与功能应用非常相似,但是某种“特殊情境”取决于应用。对于Maybe的情况,上下文可能缺乏价值。对于元组,上下文是“伴随每个值的单一注释”。

pure<*>可以为不同的数据类型做很多不同的事情,只要它们遵守法律。

实际上,相同的数据类型可以以不同的方式应用。列表具有<*>“获取所有组合”的Applicative实例,但也包含使用辅助ZipList newtype实现的实例,其中<*>拉链列表并且pure构造无限名单。