如何阅读F#类型签名?

Fra*_*ori 13 f#

我正在努力使用F#类型的签名表示法.例如,假设您有折叠功能:

let rec Fold combine acc l =
...
Run Code Online (Sandbox Code Playgroud)

可能有这种类型的签名:

('a -> 'b -> 'a) -> 'a -> list<'b> -> 'a
Run Code Online (Sandbox Code Playgroud)

我会读到的

一个有三个参数的函数:

  • 一个带'a,a'b并返回a'的函数
  • 'a
  • 'b

并返回'a.

但是,对于我的穴居人大脑来说,将其表达为更有意义

('a, 'b -> 'a), 'a, list<'b> -> 'a
Run Code Online (Sandbox Code Playgroud)

我确定有一个语义原因,为什么参数用箭头与函数返回类型完全相同,但不知何故我错过了它,并且到目前为止在书籍/文章中没有找到明确的解释.每当我看到类型签名时,我都要花很多时间来理解它.我觉得我只是错过了让"解密"显而易见的那一小块难题.

有人可以赐教吗?

Jul*_*iet 15

我确定有一个语义原因,为什么参数用箭头与函数返回类型完全相同,但不知何故我错过了它,并且到目前为止在书籍/文章中没有找到明确的解释.

你正在阅读第一个功能是正确的.对于即时解密,类型签名表示如下:

val functionName = inputType1 -> inputType2 -> ... -> inputTypeN -> returnType
Run Code Online (Sandbox Code Playgroud)

通常,箭头符号表示功能是可以进行的.

// val add4 : int -> int -> int -> int -> int
let add4 a b c d = a + b + c + d;;

// val f : (int -> int)
let f = add4 1 2 3 // returns (int -> int) waiting for last argument
Run Code Online (Sandbox Code Playgroud)

因为函数是curry,你可以在技术上写这样:

// val add4 : int -> int -> int -> int -> int
let add4 = (fun a -> (fun b -> (fun c -> (fun d -> a + b + c + d))));;

// val f : (int -> int)
let f = fun x -> add4 1 2 3 x
Run Code Online (Sandbox Code Playgroud)

如果你考虑一下,add4签名就相当于:

val add4 : int -> (int -> (int -> (int -> int) ) )
Run Code Online (Sandbox Code Playgroud)

我相信我们使用箭头符号,因为当我们明确地讨论如上所示的参数时,它类似于函数的结构.


mur*_*d99 6

签名是以这种方式编写的,因为所谓的Currying.稍微更准确的描述函数的方法是它接受一个(函数接受a 'a并将函数从a 返回'b到a 'a)并返回一个函数,该函数接受a 'a并将函数从a返回list<'b>到a 'a.因此,类型签名可以重写为

('a -> 'b -> 'a) -> ('a -> (list<'b> -> 'a))
Run Code Online (Sandbox Code Playgroud)


kvb*_*kvb 5

您可以在F#中编写一个类似的函数,其类型与您提议的类似(但在F#中它将被写为('a * 'b -> 'a) * 'a * list<'b> -> 'a.但是,现有函数的优点是通过仅提供前缀可以很容易地部分应用它.参数.例如:

let sum = List.fold (+) 0
Run Code Online (Sandbox Code Playgroud)

使用你的定义,你必须写

let sum l = List.fold((fun (x,y) -> x + y), 0, l)
Run Code Online (Sandbox Code Playgroud)