【问题标题】:haskell function given type signature dealing with list给定处理列表的类型签名的haskell函数
【发布时间】:2015-02-15 20:26:34
【问题描述】:
mapNew :: a -> (a -> b -> c) -> [b] -> [c]

给定这个类型签名,mapNew 应该是一个什么样的函数?

我知道返回类型是列表。

【问题讨论】:

  • 这是一个函数,它将相同的a 和来自[b] 的每个函数应用于作为第二个参数传递的函数并产生[c]。所以实现可能只是a -> (a -> b -> c) -> b -> cmap 超过[b]

标签: haskell


【解决方案1】:

这看起来很像一个家庭作业问题。如果是,我强烈建议您尝试自己回答这个问题。话虽如此,我将引导您了解我将如何制定此问题的答案,并希望让您对如何处理此类问题有所了解。

我们知道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 的第一个参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    • 2021-05-12
    • 1970-01-01
    • 2021-01-23
    相关资源
    最近更新 更多