这看起来很像一个家庭作业问题。如果是,我强烈建议您尝试自己回答这个问题。话虽如此,我将引导您了解我将如何制定此问题的答案,并希望让您对如何处理此类问题有所了解。
我们知道mapNew 的类型为a -> (a -> b -> c) -> [b] -> [c]。这看起来很像现有的 Prelude 函数map :: (a -> b) -> [a] -> [b]。所以我们可能想用map 来写我们的答案。
mapNew :: a -> (a -> b -> c) -> [b] -> [c]
mapNew a f bs = ...
我们总是从写出带有参数的函数开始,这样我们就可以看到我们必须处理哪些部分。知道我们只有一个 a 并且需要始终将 f 传递给 bs 中的每个元素 b,我们可以为这个部分应用添加一个 where 子句:
mapNew :: a -> (a -> b -> c) -> [b] -> [c]
mapNew a f bs = ...
where fa :: b -> c
fa = f a
鉴于此,我们现在可以用map 写出我们的答案。
mapNew :: a -> (a -> b -> c) -> [b] -> [c]
mapNew a f bs = map fa bs
where fa :: b -> c
fa = f a
大多数 haskell 程序员会将此定义简化为:
mapNew :: a -> (a -> b -> c) -> [b] -> [c]
mapNew a f bs = map (f a) bs
因为(f a) 正是部分应用函数fa。此外,我们可以将该表达式 eta-reduce 为:
mapNew :: a -> (a -> b -> c) -> [b] -> [c]
mapNew a f = map (f a)
这个答案的关键在于“知道我们只有一个a,并且需要始终将bs 中的每个元素b 传递给f”。我怎么知道?
由于参数多态性,我们无法检查a 类型的任何值。这意味着我们可以使用的唯一a 类型的值是传递给mapNew 的值。此外,由于f 采用单个b 并产生单个c,我们知道我们必须首先从提供的列表中获取b 才能将f 应用于它。这正是map 所做的事情,通过将f 部分应用于a,我们得到了我们想要传递给map 的第一个参数。