为什么列表Applicative实例不执行一对一应用程序?

nmd*_*mdr 3 haskell applicative

我正在ApplicativeHaskell的Haskell编程中阅读Haskell.为了更好地理解它,我想出了以下Applicative列表定义:

-- Named as pure' and "app" to avoid confusion with builtin versions 
class Applicative' f where
 pure' :: a -> f a
 app :: f (a->b) -> f a -> f b

instance Applicative' [] where
 pure' x = [x]
 app _ [] = []
 app [g] (x:xs) = [(g x)] ++ app [g] xs
 app (g:gs) (x:xs) = [(g x)] ++ app gs xs

-- fmap functions could be defined as:
fmap1' :: (Applicative' f)=>(a->b) -> f a -> f b
fmap1' g x = app (pure' g) x

fmap2' :: (Applicative' f)=>(a->b->c) -> f a -> f b -> f c
fmap2' g x y = app (app (pure' g) x) y


fmap3' :: (Applicative' f)=>(a->b->c->d) -> f a -> f b -> f c -> f d
fmap3' g x y z = app (app (app (pure' g) x) y) z
Run Code Online (Sandbox Code Playgroud)

使用的一个例子 fmap2' 如下:

Ok, one module loaded.
*Main> g = \x y -> x*y
*Main> arr1 = [1,2,3]
*Main> arr2 = [4,5,6]
*Main> fmap2' g arr1 arr2
[4,10,18]
*Main>
Run Code Online (Sandbox Code Playgroud)

但是列表Applicative函数的标准定义<*>定义为:

gs <*> xs = [g x | g <- gs, x <- xs]
Run Code Online (Sandbox Code Playgroud)

从而导致

pure (*) <*> [1,2], [3,4]
[3,4,6,8]
Run Code Online (Sandbox Code Playgroud)

我想知道为什么它的定义方式for all arr1, for all arr2, apply function而不是take corresponding elements arr1, arr2 apply function.我想第一个定义可能更有用吗?这个选择有什么具体原因吗?

lef*_*out 5

这基本上是ZipList应用实例.主要区别在于

pure x = repeat x
Run Code Online (Sandbox Code Playgroud)

而不是你的pure x = [x].

这是履行适用法律所必需的.也就是说,您的实施违反了交换法:

[id, id] <*> pure 1 ? [id,id] <*> [1]
                    ? [id 1] ++ ([id] <*> [])
                    ? [id 1] ++ []
                    ? [1]
‡ pure ($ 1) <*> [id,id] ? [1,1]
Run Code Online (Sandbox Code Playgroud)

对于无限要求pure使得ZipList有些古怪的做法.标准实现基本上是最自然的有限实现.可以说,如果前奏中存在有限数组和可能无限列表的单独类型,并且列表中有ZipList实例,则会更好.

根据评论,你的实现实际上也很好,如果你只需要填写两个列表.太好了!

  • (调整过的)实例确实合法 - "(<*>)"归结为扩展较短的列表然后使用`ZipList`实例; 这样做不可能失败相关性.那很整齐. (2认同)

pig*_*ker 5

Applicative []生成所有可能组合行为而不是任何类型的zippy行为的基本原因是,它Applicative是一个超类,Monad并且旨在根据Monad实例存在时的行为.Monad []将列表视为失败和优先级选择,因此Applicative []实例也是如此.人们经常使用应用程序界面重构monadic代码,以减少值所需的中间名称的数量,并增加并行机会.如果这导致功能语义的重大转变,那将是非常可怕的.

除此之外,事实是,Applicative []如果你考虑空/非空和有限/共同/无限变化,你就会被选择用于实例的选择.这是为什么?

好吧,正如我在这个答案中所提到的,在我们开始担心价值之前,每Applicative f一个都是以数据Monoid (f ())形状结合起来的.列表就是一个很好的例子.

[()]基本上是数字的类型.数字在很多方面都是幺半群.

Applicative []Monad []量到选择所产生的独异1*.

同时,Applicative ZipList利用Haskell的共同混合,相当于选择由无穷大和最小生成的幺半群.

这个问题提出了一个不合法的例子,但它接近于一个例子.你会注意到<*>没有为一个空的函数列表定义,但是对于非空的函数列表,它会填充以匹配参数列表.不对称,它在参数用完时截断.有点不对劲.

随后有两个候选修复程序.

一个是在两边都是空的截断,然后你必须拿走pure = repeat你的ZipList.

另一种是排除空列表并在两侧填充.然后你会得到Applicative从产生Monoid由1和产生的数字最大.所以它根本不ZipList存在.这就是我PadMe这个答案中所说的.你需要排除0的原因是,对于输出中的每个位置<*>,你需要指向两个输入中的函数及其参数(分别)来自的位置.如果你没有任何东西可以垫,你不能垫.

这是一个有趣的游戏.选择一个Monoid数字,看看你是否可以将它变成Applicativefor列表!