我不会直接给出这个作业的解决方案,而是用更笼统的术语来解释它。您现在可能不了解其中的大部分内容,但至少应该能够挑选出您需要的内容!
map 只是 Functor 将函数“提升”为函子函数的方法的专用版本(用于列表函子):
class Functor f where
fmap :: (a->b) -> f a->f b
现在,列表是一种特别强大的函子:applicative 函子,甚至是 monad。 Applicative 让许多程序员感到困惑,但您的示例非常适合:
前奏曲> :m +Control.Applicative
Prelude Control.Applicative> let f1 xs ys = (+) xs ys
Prelude Control.Applicative> :t f1
f1 :: (Num b, Applicative f) => f b -> f b -> f b
Prelude Control.Applicative> f1 [1,2,3,4] [5,6,7,8]
[6,7,8,9,7,8,9,10,8,9,10,11,9,10,11,12]
当然你也可以简单写
Prelude Control.Applicative> (+) [1,2,3,4] [5,6,7,8]
[6,7,8,9,7,8,9,10,8,9,10,11,9,10,11,12]
看起来很简单,但它是如何工作的? Applicative 类的令人困惑之处在于,您不断地将 curried 函数插入函子中,在其中部分评估它们,并以某种方式从外部检索结果。使用 monad 时,您不会这样做,因此它们更容易掌握。只使用Monad类型的类,也可以做例子(Monad比Applicative严格)。
Haskell 列表推导式实际上只是 monad 操作的语法糖!
[ x+y | x <- xs, y <- ys ]
是糖
xs >>= \x -> ys >>= \y -> return (x+y)
或带有额外的括号:
xs >>= ( \x -> ( ys >>= ( \y -> return (x+y) ) ) )
好吧,您可以使用以下规则将其转换为只有 map 和 concat 的东西:
-
ys >>= (\y -> return (f y)) 与 map f ys 相同。
-
zs >>= (\z -> g z) 与 concat (map g zs) 相同。