Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 为什么zipWith.zipWith有效?_Haskell_Zipwith - Fatal编程技术网

Haskell 为什么zipWith.zipWith有效?

Haskell 为什么zipWith.zipWith有效?,haskell,zipwith,Haskell,Zipwith,我正在实现一个函数combine::[[a]]->[[b]]->(a->b->c)->[[c]]],该函数给定两个二维列表,将给定函数f::a->b->c应用于二维列表的条目。换言之: [[a, b, c], [[r, s, t], [[f a r, f b s, f c t], combine [d, e, g], [u, v, w], f = [f d u, f e v, f g w], [h, i

我正在实现一个函数
combine::[[a]]->[[b]]->(a->b->c)->[[c]]]
,该函数给定两个二维列表,将给定函数
f::a->b->c
应用于二维列表的条目。换言之:

          [[a, b, c],    [[r, s, t],          [[f a r, f b s, f c t], 
combine    [d, e, g],     [u, v, w],   f   =   [f d u, f e v, f g w],
           [h, i, j]]     [x, y, z]]           [f h x, f i y, f j z]]
现在我怀疑
combine=zipWith。zipWith
,因为我已经尝试过了,它给了我预期的结果,例如

(zipWith . zipWith) (\x y -> x+y) [[1,2,3],[4,5,6]] [[7,8,9],[10,11,12]]
给出了预期的结果
[[8,10,12],[14,16,18]
,但我不明白为什么会这样,因为我不明白
zipWith的类型是如何工作的。zipWith
原来是
(a->b->c)->[[a]]->[[b]]->[[c]]


()
此处是否仍在执行通常的函数合成?如果是这样,您能解释一下这是如何应用于
zipWith

来推断表达式的类型,例如
zipWith。zipWith
,你可以用下面的方式在头脑中模拟统一

第一个
zipWith
具有类型
(a->b->c)->([a]->[b]->[c])
,第二个
(s->t->u)->([s]->[t]->[u])
(。
具有类型
(m->n)->(o->m)->(o->n)

要进行打字检查,您需要:

  • m
    =
    (a->b->c)
  • n
    =
    ([a]->[b]->[c])
  • o
    =
    (s->t->u)
  • m
    =
    ([s]->[t]->[u])
    =
    a
    =
    [s]
    b
    =
    [t]
    c
    =
    [u]
    ,因为第一个约束

然后返回的类型是
o->n
,它是
(s->t->u)->([a]->[b]->[c])
,从约束中进一步
(s->t->u)->([[s]]->[[t]]->[[u]])
是的,
是正常的函数组合运算符:

Prelude> :type (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
一种方法是,它接受一个
a
值,首先调用
a->b
函数,然后使用该函数的返回值调用
b->c
函数。结果是一个
c

查看
(zipWith.zipWith)
的另一种方法是执行eta扩展:

Prelude> :type (zipWith . zipWith)
(zipWith . zipWith) :: (a -> b -> c) -> [[a]] -> [[b]] -> [[c]]

Prelude> :t (\x -> zipWith $ zipWith x)
(\x -> zipWith $ zipWith x)
  :: (a -> b -> c) -> [[a]] -> [[b]] -> [[c]]

Prelude> :t (\x -> zipWith (zipWith x))
(\x -> zipWith (zipWith x))
  :: (a -> b -> c) -> [[a]] -> [[b]] -> [[c]]
zipWith
本身的类型:

Prelude> :type zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
因此,在上面的lambda表达式中,
x
必须是
(a->b->c)
,因此带有x的
zipWith必须具有
[a]->[b]->[c]
类型

如果
a1
[a]
b1
[b]
,而
c1
[c]
,则带
zipWith
外部
zipWith
也需要一个函数


因此,通过替换,
zipWith(zipWith x)
必须具有类型
[[a]]->[[b]->[[c]]
,因此lambda表达式的类型是
(a->b->c)->[[a]->[[b]->[[c]]

另一种看待它的方式是,使用压缩操作的列表形成一个
应用程序,以及(嵌套)的
Applicative
s仍然是
Applicative

λ import Control.Applicative
λ import Data.Functor.Compose
λ let l1 = ZipList [ZipList [1,2,3], ZipList [4,5,6]]
λ let l2 = ZipList [ZipList [7,8,9], ZipList [10,11,12]]
λ getCompose $ (+) <$> Compose l1 <*> Compose l2
ZipList {getZipList = [ZipList {getZipList = [8,10,12]},
                       ZipList {getZipList = [14,16,18]}]}
λ导入控制。适用
λimport Data.Functor.Compose
λ设l1=ZipList[ZipList[1,2,3],ZipList[4,5,6]]
λlet l2=ZipList[ZipList[7,8,9],ZipList[10,11,12]]
λgetCompose$(+)Compose l1 Compose l2
ZipList{getZipList=[ZipList{getZipList=[8,10,12]},
ZipList{getZipList=[14,16,18]}]}

<代码> ZPLIST < /Cord> NeXType是必需的,因为“裸”列表有不同的<代码>应用程序实例,它形成了所有组合而不是拉链。实际上,您也可以考虑查看此类操作的类型。BTW,可以将加法运算符作为函数:<代码>(ZIPOS.ZIPOP)(+)[[1,2,3],[4],5],6]。][7,8,9],[10,11,12]

或<代码>()。((+))l1 l2
数据。Functor.Compose
@Redu虽然更紧凑,但我发现新的无类型版本更难理解。是的,我必须同意,无点有时乍一看可能会令人困惑。基本上是
()。(++)
是“\xy->”(++)xy”。