【问题标题】:Term to call a function with empty parameter使用空参数调用函数的术语
【发布时间】:2017-09-03 23:25:12
【问题描述】:

在函数式编程中,调用不接受参数的函数的正确名称是什么?例如:

// 2 types of execute functions
type Function =
    | UnitFunction of (unit -> unit)
    | OperandFunction of (unit16 -> unit)

let nop () =
    ()

let shiftRegisterA operand =
    registers.A <- registers.A <<< operand

nop 可以称为UnitFunctionshiftRegisterA 可以称为OperandFunction吗?

【问题讨论】:

    标签: .net f# functional-programming terminology language-design


    【解决方案1】:

    您在这里所指的通常称为函数的arity。因此,没有参数的函数将被称为空函数和具有单个参数的函数 - 一元函数。

    虽然您仍然可以在 F# 函数的上下文中使用该术语并获得普遍理解,但这并不完全准确。 F# 函数总是采用单个参数并返回单个值,因为函数默认是 curried。

    在您的情况下,nop 的类型为 unit -&gt; unit。这意味着它接受unit 类型的单个参数(该类型的唯一() 值),并返回unit 类型的结果。尽管如此,这仍然使它成为一元函数。

    【讨论】:

      【解决方案2】:

      在汇编编程中调用函数是将参数压入堆栈(或寄存器,取决于调用约定)然后跳转到函数地址的过程。

      在 Java、C#、C 等更高级的语言中,这个过程对我们来说或多或少是隐藏的。但是,当我们调用不带参数的函数时,我们会看到它的痕迹,即void

      在 F#、haskell 等函数式编程语言中,函数的概念更接近于从单个输入产生答案的数学函数。

      要查看 F# 中的所有函数都接受单个输入,让我们看看以下函数:

      // val f: (int*int) -> int
      let f (x,y) = x + y
      

      f 接受一对整数并产生一个整数。从 f 的角度来看,这对是一个单独的值,它解构以产生答案。

      // val g: int -> int -> int
      let g x y = x + y
      

      这显然看起来像是一个接受两个整数来产生一个整数的函数,但如果我们稍微重写一下,我们会发现情况并非如此:

      // val h: int -> int -> int
      let h x = fun y -> x + y
      

      h 等价于g,但这里我们看到h 实际上采用一个整数,该整数产生一个函数,该函数接受一个整数来产生一个整数。

      签名中的-&gt; 是右关联的,我们添加了括号,我们可以更清楚地看到gh 实际上是采用单个输入。

      // val g: int -> (int -> int)
      let g x y = x + y
      
      // val h: int -> (int -> int)
      let h x = fun y -> x + y
      
      let gx = g 1 2
      let gy = (g 1) 2
      let hx = h 1 2
      let hy = (h 1) 2
      

      在我看来,F# 中的函数比 C#/Java 中的函数具有更高的抽象级别,因为 C#/Java 函数在概念上比 F# 函数更接近汇编语言函数。

      此外,如果每个函数都需要一个参数,那么对于不接受任何参数的函数来说意义不大。

      但是这个函数呢?

      // val i: unit -> int
      let i () = 3
      

      它不接受产生 3 的任何参数吗?不,它接受单位值(),这只是unit 类型中的值。

      在 Haskell 中,它们为接受 void 并产生答案的函数命名:

      absurd :: Void -> a
      

      值也许可以看作是一个不带参数的函数,但我不是范畴论专家。

      回到示例代码:

      type Function =
      | UnitFunction of (unit -> unit)
      | OperandFunction of (unit16 -> unit)
      

      函数式方法是这样的:

      type Abstraction =
      | Concrete of obj
      | Function of Abstraction -> Abstraction
      

      Abstraction 是一个值或一个函数。

      从代码来看,它似乎模拟了一些类似于汇编语言的东西,因此在这种情况下,可以将函数视为推送参数并跳转到一个地址。

      type Function =
      | VoidFunction    of (unit -> unit)
      | UnaryFunction   of (unit16 -> unit)
      | BinaryFunction  of (unit16 -> unit16 -> unit)
      

      希望这很有趣。

      PS。

      看起来unit 类型是一个小细节,但在 IMO 中它可以带来很多好处。

      • 无需声明。
      • 简化泛型编程(void 情况通常需要特殊情况,请考虑Task&lt;'T&gt;Task)。
      • 让我们可以像数学函数一样思考函数,而不是跳转到内存中的地址。

      【讨论】:

      • Re: 特殊的void 情况,C# 中最不和谐的一种是ActionFunc 类型之间的拆分。
      猜你喜欢
      • 1970-01-01
      • 2022-01-10
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      • 2016-11-19
      • 1970-01-01
      • 2012-08-25
      • 1970-01-01
      相关资源
      最近更新 更多