繁体   English   中英

输入函数式编程(OCaml)

[英]Type in functional programming (OCaml)

我正在学习函数式编程,并且不了解OCaml中的类型,并且我还没有发现真正有用的东西。

我有以下代码:

let rec map2 f l1 l2 =
          match (l1,l2) with
          ([], _) -> []
        | (_, []) -> []
        | (x::l1s,y::l2s) -> (f x y) :: map2 f l1s l2s;;


let pick n m =
      if n > m then (fun b x -> if b then x+1 else x*2)
      else (fun b x -> if b then x+2 else x*4);;

map2 (pick 7 9) [true;false] [3;4;5;6];;

我发现很难理解了解此类功能类型的步骤(map2,pick)。

我知道一点点的签名是如何工作的,正确的关联属性和符号“'”指的是一个泛型类型。

解:

pick: 'a -> 'a -> bool -> int -> int = <fun>
map2: ('a->'b->'c) -> 'a list -> 'b list -> 'c list

我不明白为什么bool-> int以及为什么map bool不在函数参数中。

任何对书籍,链接的引用都欢迎

pick: 'a -> 'a -> bool -> int -> int = <fun>
map2: ('a->'b->'c) -> 'a list -> 'b list -> 'c list

您在这里看到的是函数编程中称为currying的过程 为了理解这一点,让我们考虑一个更简单的示例。 假设您有一个函数f ,它接受2个参数XY ,并输出Z 我们通常的写法是

f(X, Y) = Z

让我们以不同的方式看待这一点-我们有一个函数f ,如果给它X ,然后给Y ,它将给我们Z 如果我们仅给f 1自变量X会发生什么? 让我们测试一下!

let plus a b = a + b;;

这段代码定义了一个plus函数,该函数接受2个参数ab并返回它们的总和。 如果键入plus 1 1;; 进入utop ,它将给您2 现在,键入时的输出

plus 1;;

- : int -> int = <fun>

这意味着plus(1)实际上会产生一个函数,该函数接受一个int并输出一个int 等一下,最初我们有一个产生整数的函数,突然之间,同一函数产生了...功能? 这是怎么回事?

这里的关键思想是将函数视为一个过程,该过程一个接一个地消耗参数 在这种精神的功能plus上面就是这样消耗2个参数的方法:如果你给它只是1周的说法,这将拖延和等待第二个参数。 这个停顿的过程与消耗1个参数的过程完全相似:给它剩余的成分,它将开始磨碎以提供预期的输出。

为了了解这种观点如何帮助您理解示例中编写函数签名的晦涩方式,让我们看一下函数pick

let pick n m =
  if n > m then (fun b x -> if b then x+1 else x*2)
  else (fun b x -> if b then x+2 else x*4);;

pick接受2个参数nm ,并输出函数f接受2个参数bx f的定义取决于比较。 如果n > m ,则它输出一个函数fun bx其定义是if b then x+1 else x*2 否则,它输出一个函数fun bx其定义是if b then x+2 else x*4

如果我们根据上述理解为pick写一个粗略的签名,它将类似于:

pick: (n, m) -> (function f that takes in b and x, and output some number)

根据我们对curring的理解, pick就像一个消耗n ,然后消耗m 所以签名也可以这样写:

pick: n -> m -> (function f that takes in b and x, and output some number)

哦,嘿,这个函数f也可以看作是一个先消耗b然后再消耗x的进程,所以我们也可以这样写:

pick: n -> m -> (b -> x -> some number)

看起来非常类似于:

pick: 'a -> 'a -> bool -> int -> int = <fun>

现在,关于OCaml到底是怎么知道b应该是bool ,而xsome number应该是int ,OCaml具有一个称为类型推断的功能 基本上,编译器会查看您对变量执行的操作,并尝试猜测它们的类型。 例如,我查看代码中的if b ,所以b可能应该是bool

总而言之 ,写函数签名的晦涩方式被称为currying ,而OCaml如何知道bbool是通过OCaml中的一种称为类型推断的特征来实现的。 这应该使搜索更容易。

如果查看pick,则会看到它接受2个参数,然后返回一个函数。 它返回的是(与其他乐趣相同):

(fun b x -> if b then x+1 else x*2)

“ if”构造的形式为if <bool> then <'a> else <'a> 所以b必须是布尔值,而x仍然可以是'a。 更深入的是x+1 所以x必须int ,结果是int了。

因此,上面的函数是bool -> int -> int并且在pick类型中显示hat。

至于map2:map2函数可以使用形式为'a -> 'b -> 'c任何函数作为第一个参数。 在您的示例中,您传递了bool -> int -> int但这并不将map2限制为该类型。 您的代码可以继续

let pick_f n m =
      if n > m then (fun b x -> if b then x +. 1. else x *. 2.)
      else (fun b x -> if b then x +. 2. else x *. 4.);;

map2 (pick_f 7 9) [true;false] [3.;4.;5.;6.];;

pick_f: 'a -> 'a -> bool -> float -> float = <fun>

使用相同的map2函数,但此处将bool -> float -> float作为第一个参数的类型。 map2函数是多态的(您称为泛型),可以使用许多类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM