【问题标题】:Why Haskell takes one argument为什么 Haskell 接受一个论点
【发布时间】:2016-05-05 01:27:33
【问题描述】:

我正在试图弄清楚“Currying”背后的因果逻辑,结果如下:

  1. 多参数函数可以表示为元组(将多个不同类型的参数组合为一个参数)和列表(将多个具有相同类型的参数组合为一个参数)。所以所有函数都可以表示为单参数函数。
  2. 所以在Haskell中,函数只有一个参数。我们如何实现多参数函数。
  3. 使用柯里化。柯里化是一种实现多个争论函数的方法。

我认为上述逻辑 1 -> 2 -> 3 难以回答“为什么使用柯里化”。对于语句 3,也可以将多个元组或列表组合为单个参数来实现多参数功能。

似乎陈述 1 不是陈述 2 的正确原因。我确定 2->3 是正确的推理,但 2 背后的原因是什么?为什么 Haskell 作为一种函数式语言只接受一个参数?

大多数书籍都将陈述 2 视为公认的事实。有人知道2背后的原因吗?或者有人知道“为什么要使用咖喱”背后的正确逻辑吗?

【问题讨论】:

  • 你问,“为什么要使用柯里化?”,这意味着在某些时候有人想,“让我们使用柯里化来解决我们遇到的语言设计问题。”。但事实并非如此。有人想,“让我们做一种简单、优雅、富有表现力、方便、安全、灵活的语言吧。”。这些问题的解决方案是使用具有归纳类型的 lambda 演算、良好的类型系统和有点不寻常的归约策略。 “使用柯里化”不是解决任何这些问题的方法,而是解决这些问题的系统中巧合的方便工具。
  • 如果您将元组视为产品类型(如:Bool 有两个居民,Maybe Bool 有三个居民,(Bool, Maybe Bool) 有六个居民),那么函数类型就是指数。由于e^(x * y) = (e^x)^y,您始终可以将(x, y) -> e 类型的函数重写为y -> (x -> e) 类型的类似函数。简而言之,这是咖喱。因为您始终可以重写此类函数(在这种情况下,成本相对较低),所以您不需要将多参数函数作为基本概念,否则会使您的语言定义复杂化。

标签: haskell currying


【解决方案1】:

决定使用柯里化作为多参数函数的首选方法有两个原因。首先,Haskell 深深植根于使用柯里化的 lambda 演算。其次,currying 可以很容易地进行部分应用,这是一个非常有用的语言方面。

【讨论】:

    【解决方案2】:

    功能

    f x y = x + y
    

    有类型(假设x & yIntegers)

    f :: Integer -> Integer -> Integer
    

    这是一样的

    g :: Integer -> (Integer -> Integer)
    

    这意味着f 是一个接受Integer 并返回一个新函数的函数,该函数也接受Integer 并返回Integer。柯里化是一个过程,其中一个接受多个参数的函数实际上被评估为一系列接受一个参数的函数。

    Currying 使得部分应用函数变得非常容易,如下所示

    plusTwo :: Integer -> Integer
    plusTwo = f 2
    

    上面的代码只是将2 应用于f 并将名称plusTwo 绑定到结果函数。

    这使得开发人员可以非常轻松地将常见行为抽象到一个地方。

    【讨论】:

      【解决方案3】:

      首先,您需要记住 Haskell 完全基于 Lambda 演算。它是根据科学编程模型制作的(尽管这并不意味着该语言只有科学用途)。

      我认为你错了,因为它可以显示为元组或列表,所以它不会只得到一个参数,即使这是一个非常聪明的解释。

      由于 Currying,Haskell 只接受一个参数:

      f(x,y) = f(x)(y)

      其中 f(x) 返回一个接受一个参数的函数。柯里化是整个“返回函数的函数”方案。因此,当您使用 f(x)(y) 时,您实际上是在将 'y' 传递给 'f(x)' 函数。

      经典例子:

      add :: a->(a->a)
      add(x) = x'+'
      

      由于“+”是一个函数,这意味着它需要另一个参数,我们可以:

      add(3)(5) == 8
      

      我们没有将两个参数都传递给 add,只传递一个参数,这样它就可以生成 '+' 来获取另一个参数。

      在你思考之后,这会很有意义,我们可以继续说明原因。

      嗯,主要是合成糖,但非常强大。例如,我们可以在不指定参数的情况下基于 other 定义函数:

      add = '+'
      

      突然间,我给函数赋值而没有提及参数(当然假设它们的类型声明匹配)。这有很多其他的可能性,并且大大简化了抽象。

      这里有很好的答案和很好的例子:https://softwareengineering.stackexchange.com/questions/185585/what-is-the-advantage-of-currying

      【讨论】:

      • 感谢您提醒 Haskell 是基于 lamda 演算的。我已经通过 lambda 演算找到了我认为非常接近的答案:首先,lamda 演算使用它的定义被证明是通用的从数学的角度来看,所有计算都可以用它来表达。其次,lambda 的定义之一是每个函数只接受一个参数。那么,如果 lambda 演算不能提供多参数函数,它如何被称为通用的。答案当然可以,只要使用Curryring(高阶函数)。
      • 是的,你做得很好。
      猜你喜欢
      • 2011-02-14
      • 2020-09-20
      • 1970-01-01
      • 2011-01-15
      • 2021-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多