我猜,你得到的是从尝试到foldr
到foldl'
简单地切换错误:
myConcat xs ys = foldl' (:) ys xs
产生的误差(用我的拥抱REPL):
ERROR - Type error in application
*** Expression : foldl' (:) xs ys
*** Term : (:)
*** Type : a -> [a] -> [a]
*** Does not match : [a] -> a -> [a]
在公告最后两行(提供的类型和预期类型)[a]
和a
的位置处于相反的位置。这意味着我们需要一个类似于(:)
的函数,但它以相反的顺序参数。
Haskell有一个功能,它为我们做到这一点:flip
函数。基本上,flip
相当于
flip :: (a -> b -> c) -> (b -> a -> c)
flip f y x = f x y
即,flip
取二进制函数作为参数,并返回原来的另一个二进制函数,其自变量被反转(“翻转”)。因此,尽管(:)
的类型为a -> [a] -> [a]
,但我们看到flip (:)
的类型为[a] -> a -> [a]
,因此它是foldl'
的参数的完美候选者。
使用flip
,我们现在有这样的代码:
myConcat xs ys = foldl' (flip (:)) ys xs
此结果与事实foldl'
的类型是(a -> b -> c) -> a -> [b] -> c
带参数运行此[1..5]
和[6..10]
,我们得到的[5,4,3,2,1,6,7,8,9,10]
结果,这几乎是我们想要的。唯一的问题是结果中第一个列表倒退。添加一个简单的调用reverse
赋予我们的myConcat
最后定义:
myConcat xs ys = foldl' (flip (:)) ys (reverse xs)
纵观这一过程显示了经常出现的好东西之一,当写Haskell代码:当你碰到一个问题,您可以一次解决一个(小)步骤。当你已经有一个工作实现时,这是尤其如此,而你只是试图编写另一个实现。需要注意的是,如果您更改了实现的一部分(在这种情况下,将foldr
更改为foldl'
),那么其他许多其他必需的更改就会脱离类型定义。剩下的少数是可以很容易找到的纠正问题,无论是通过运行测试用例,还是通过查看所使用函数的确切性质。 PS:任何可以清理最后一行代码的Haskell家伙,都可以随时这样做。虽然它并不可怕,但我不觉得它很漂亮。不幸的是,我对Haskell不太了解。
您的帖子真实我帮助了我。感谢您的解释:) – Adi 2011-06-17 12:54:07