【问题标题】:Haskell - Filter, CurryingHaskell - 过滤器,柯里化
【发布时间】:2020-06-22 23:47:48
【问题描述】:

我只想知道我对柯里化函数的以下理解是否正确。 我想filter 列表中的所有元素> 4。我可以这样实现:

filter (>4) [1..10]
  1. (>) 被定义为Ord a => a -> a -> Bool,这就是为什么它不能被过滤。
  2. (>4) 定义为 (Ord a, Num a) => a -> Bool。函数 (>) 现在被柯里化了,仍然需要一个参数。
  3. 由于 2.,(>4) 可以传递给过滤器。
  4. 每个传递给 filter 的 List-Element 都将传递给 (>4),并且 filter 将验证谓词并返回结果。

这对吗?

【问题讨论】:

  • 这或多或少是正确的。 (>4) 等价于 \x -> x > 4 或更规范的 \x -> (>) x 4,因此您构造一个函数,如果 x > 4 将检查值 x
  • (>4)中缀运算符分段wiki.haskell.org/Section_of_an_infix_operator
  • 这是正确的。您可以使用 ghci 轻松验证所有涉及的类型:例如:t (>4) (Ord a, Num a) => a -> Bool:t (filter (>4)) (filter (>4)) :: (Ord a, Num a) => [a] -> [a]
  • @MoritzSchmidt:不,(<)总是咖喱。您在这里所做的是执行部分应用程序
  • @MoritzSchmidt uncurried 函数是这样调用的:f (a1,a2,..,aN),将参数元组作为输入。相反,一个柯里化函数被称为f a1 a2 .. aN,并且可以部分应用为f a1f a1 a2 等。这与(>4) 几乎无关,这是\x -> x > 4 的Haskell 特殊节语法。请注意,此部分与部分应用程序 ((>) 4) 非常不同,后者将等效于 \x -> 4 > x,颠倒比较(!)

标签: haskell filter functional-programming currying


【解决方案1】:

这个推理或多或少是正确的。 (>) 是一个带有签名的函数:

(>) :: Ord a => a -> (a -> Bool)

所以它是一个函数(与 Haskell 中的任何其他函数一样)采用 one 参数,这里返回一个函数a -> Bool

因此问题是,如果我们使用filter (>) [1,4,2,5],那么我们将调用(>) 1,这将因此返回一个函数a -> Bool,但filter 不能使用它,它需要从列表中获取元素并返回 Bool 的函数,而不是返回映射到 Bool 的函数的函数。

因此我们可以使用:

filter ((<) 4) [1,4,2,5]

因此我们在这里执行partial application [Haskell-wiki] 的功能。这意味着我们生成了一个函数(<) 4 :: (Num a, Ord a) => a -> Bool。因此,我们可以使用该函数进行过滤,因此它将返回 [5]

我们还可以使用 lambda 表达式创建一个函数来“交换”参数的顺序:

filter (<b>\x -&gt; (&gt;) x 4</b>) [1,4,2,5]

这里对于一个值x,我们将调用((&gt;) x) 4,这将因此返回一个Bool

由于经常会为中缀运算符的两侧之一提供一个值,因此 Haskell 有sectioning syntax for an infix operator [Haskell-wiki]

  • (2^)左边部分)等价于(^) 2,或者更详细的\x -&gt; 2 ^ x
  • (^2)右侧部分)等价于flip (^) 2,或更冗长的\x -&gt; x ^ 2

所以我们可以将最后一个表达式改写为:

filter <b>(&gt; 4)</b> [1,4,2,5]

【讨论】:

  • 非常感谢威廉。还有一个问题:如果我使用 ghci,请确定 (>) 的签名,如下所示::t (&gt;) 我得到:(&gt;) :: Ord a =&gt; a -&gt; a -&gt; Bool 而不是 (&gt;) :: Ord a =&gt; a -&gt; (a -&gt; Bool) 像你一样。这是为什么呢?
  • @MoritzSchmidt:因为(-&gt;)右结合运算符,所以a -&gt; b -&gt; c等价于a -&gt; (b -&gt; c),这里解释为:wiki.haskell.org/Partial_application
  • @MoritzSchmidt 没有区别,a1 -&gt; a2 -&gt; ... -&gt; aNa1 -&gt; (a2 -&gt; (a3 -&gt; ... aN)))) 相同。 GHCi 不会打印多余的括号,但您可以假装它们在那里。
猜你喜欢
  • 2019-01-28
  • 1970-01-01
  • 1970-01-01
  • 2020-02-25
  • 2011-04-22
  • 1970-01-01
  • 1970-01-01
  • 2018-04-18
  • 1970-01-01
相关资源
最近更新 更多