(* 作用域 非掩盖的例子 *) let languages = "OCaml,Perl,C++,C";; let dashed_languages = let language_list = String.split languages ~on:','inString.concat ~sep:"-" language_list ;; language_list;;
(* 作用域 掩盖外层定义的例子 *) let languages = "OCaml,Perl,C++,C";; let dashed_languages = let languages = String.split languages ~on:','inString.concat ~sep:"-" languages ;; languages;;
顶层环境运行结果
1 2 3 4 5 6 7 8
# let dashed_languages = let language_list = String.split languages ~on:','in String.concat ~sep:"-" language_list;; val dashed_languages : Core.Std.String.t = "OCaml-Perl-C++-C" # language_list;; Characters 0-13: language_list;; ^^^^^^^^^^^^^ Error: Unbound value language_list
掩盖外层定义,输出对比
1 2 3 4 5 6 7
# let languages = "OCaml,Perl,C++,C";; val languages : string = "OCaml,Perl,C++,C" # let dashed_languages = let languages = String.split languages ~on:','in String.concat ~sep:"-" languages;; val dashed_languages : Core.Std.String.t = "OCaml-Perl-C++-C" # languages;; - : string = "OCaml,Perl,C++,C"
List.map ~f:(fun x -> x+1) [1;2;3] ;; (* 传入另一个函数 *)
let increments = [ (fun x -> x +1) ; (fun x -> x+2) ];; (* 嵌入list *) let get_head_func func_lists = match func_lists with | [] -> (fun x -> 0) | hd::tl -> hd ;; let testfunc = get_head_func increments;; testfunc 4;;
输出结果
1 2 3 4 5 6 7 8 9 10 11
# List.map ~f:(fun x -> x+1) [1;2;3];; - : int Core.Std.List.t = [2; 3; 4] # let increments = [ (fun x -> x +1) ; (fun x -> x+2) ];; val increments : (int -> int) list = [<fun>; <fun>] # let get_head_func func_lists = match func_lists with | [] -> (fun x -> 0) | hd::tl -> hd;; val get_head_func : ('a -> int) list -> 'a -> int = <fun> # let testfunc = get_head_func increments;; val testfunc : int -> int = <fun>
多参数函数
定义命名函数的语法糖,下述两种定义方式等价:
1 2
let plusone = (fun x -> x+1);; let plusone x = x+1;;
多参数函数的语法糖,以及重写版本。
1 2 3 4 5
let abs_diff x y = abs(x-y);; let abs_diff = (fun x -> (fun y -> abs (x-y)));;
Named after the logician Haskell B. Curry (1950s).
was tring to find minimal logics that are powerful enugh to encode traditional logics.
much easier to prove something about a logic with 3 connectives than one with 20
the ideas translate directly to math (set & category theory) as well as to computer science.
Actually, Moses Schonfinkel did some of this in 1924
What's so good about curring?
In addition to simplifying the language, curring functions so that they only take one argument leads to two major wins:
We can partially apply a function.
We can more easily compose functions.
fun 支持自己的柯里化,fun匿名函数可以直接按柯里化语法写出。
部分应用,给柯里函数传入部分参数构成新函数。
1 2 3 4 5 6
let my_mod x y = if x mod y = 0thentrueelsefalse;; (* 与下面柯里化展开的函数等价 *) let my_mod = (fun x -> ( fun y -> if x mod y = 0thentrueelsefalse)) ;; let my_mod_3 = my_mod 3;;
测试结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# let my_mod x y = if x mod y = 0 thentrueelsefalse;; val my_mod : int -> int -> bool = <fun> # let my_mod = (fun x -> ( fun y -> if x mod y = 0 thentrueelsefalse));; val my_mod : int -> int -> bool = <fun> # let my_mod_3 = my_mod 3;; val my_mod_3 : int -> bool = <fun> # my_mod 10 2;; - : bool = true # my_mod 10 3;; - : bool = false # my_mod_3 10;; - : bool = false
letrec find_first_stutter list = matchlistwith | [] | [_] -> None | x :: y :: tl -> if x =y thenSome x else find_first_stutter (y::tl) ;; find_first_stutter [1;2;3;4;5;6;1;2];; find_first_stutter [1;2;2;3;3;4;4;4;];;
优先级和结合性
操作符前缀和结合性有关(详细见表),比如后面例子中|前缀为左结合,^前缀为右结合。另外由于不同于 C 等语言,传入参数至函数时没有括号分隔,所以要注意-作为减法操作符合(中缀),以及负号(前缀)使用情况,比如传参时负数要括起来。
1
Int.max 3 (-4);;
后面是关于|>和^>自定义操作符有意思的例子。行为很大程度上取决于前面描述的优先级规则.
1 2 3 4 5 6
let (|>) x f = f x;; let path = "/usr/bin:/usr/local/bin:/bin:/sbin";; String.split ~on:':' path (* |>是左结合的,从path运算内层到外层始终是字符串 *) |> List.dedup ~compare:String.compare |> List.iter ~f:print_endline ;;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# let (|>) x f = f x;; val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun> # let path = "/usr/bin:/usr/local/bin:/bin:/sbin";; val path : string = "/usr/bin:/usr/local/bin:/bin:/sbin" # String.split ~on:':' path (* |>是左结合的,从path运算内层到外层始终是字符串 *) |> List.dedup ~compare:String.compare |> List.iter ~f:print_endline;; Characters 108-118: |> List.dedup ~compare:String.compare ^^^^^^^^^^ Warning 3: deprecated: Core.Std.List.dedup [since 2017-04] Use [dedup_and_sort] instead /bin /sbin /usr/bin /usr/local/bin - : unit = ()
# let (^>) x f = f x;; val ( ^> ) : 'a -> ('a -> 'b) -> 'b = <fun> # String.split ~on:':' path ^> List.dedup ~compare:String.compare ^> List.iter ~f:print_endline;; Characters 29-39: ^> List.dedup ~compare:String.compare ^^^^^^^^^^ Warning 3: deprecated: Core.Std.List.dedup [since 2017-04] Use [dedup_and_sort] instead Characters 67-93: ^> List.iter ~f:print_endline;; ^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This expression has type string Core.Std.List.t -> unit but an expression was expected of type (Core.Std.String.t Core.Std.List.t -> Core.Std.String.t Core.Std.List.t) -> 'a Type string Core.Std.List.t = string list is not compatible with type Core.Std.String.t Core.Std.List.t -> Core.Std.String.t Core.Std.List.t
let apply_to_tuple f (first,second) = f ~first ~second;; (* 这里f作为参数传入apply *) let apply_to_tuple2 f (first,second) = f ~second ~first;; (* 我们改变标签参数列出的顺序 *)
1 2 3 4
let apply_to_tuple f (first,second) = f ~first ~second;; val apply_to_tuple : (first:'a -> second:'b -> 'c) -> 'a * 'b -> 'c = <fun> # let apply_to_tuple2 f (first,second) = f ~second ~first;; val apply_to_tuple2 : (second:'a -> first:'b -> 'c) -> 'b * 'a -> 'c = <fun>
从函数定义看,有影响。比如我们分别传递下面函数到上述两函数中,一个可行一个不可行。
1 2 3 4 5
let apply_to_tuple f (first,second) = f ~first ~second;; (* 这里f作为参数传入apply *) let apply_to_tuple2 f (first,second) = f ~second ~first;; (* 我们改变标签参数列出的顺序 *) let divide ~first ~second = first / second;; apply_to_tuple divide (3,4);; (* 可以正常工作 *) apply_to_tuple2 divide (3,4);; (* 类别不符 *)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# let apply_to_tuple f (first,second) = f ~first ~second;; val apply_to_tuple : (first:'a -> second:'b -> 'c) -> 'a * 'b -> 'c = <fun> # let apply_to_tuple2 f (first,second) = f ~second ~first;; val apply_to_tuple2 : (second:'a -> first:'b -> 'c) -> 'b * 'a -> 'c = <fun> # let divide ~first ~second = first / second;; val divide : first:int -> second:int -> int = <fun> # apply_to_tuple divide (3,4);; - : int = 0 # apply_to_tuple2 divide (3,4);; Characters 16-22: apply_to_tuple2 divide (3,4);; ^^^^^^ Error: This expression has type first:int -> second:int -> int but an expression was expected of type second:'a -> first:'b -> 'c
# apply_to_tuple divide (3,4);; Characters 16-22: apply_to_tuple divide (3,4);; ^^^^^^ Error: This expression has typefi:int -> se:int -> int but an expression was expected of type first:'a -> second:'b -> 'c # apply_to_tuple2 divide (3,4);; Characters 16-22: apply_to_tuple2 divide (3,4);; ^^^^^^ Error: This expression has type fi:int -> se:int -> int but an expression was expected of type second:'a -> first:'b -> 'c
可选参数
可以选择是否提供这个参数,可选参数也可以按任意的顺序提供。
1 2 3 4 5 6 7
let concat ?sep x y = let sep = match sep with | None -> "" | Some x -> x in x ^ sep ^ y;; concat "foo""bar";; concat ?sep:(Some"what") "foo""bar";;
1 2 3 4 5 6 7 8 9 10
# let concat ?sep x y = let sep = match sep with | None -> "" | Some x -> x in x ^ sep ^ y;; val concat : ?sep:string -> string -> string -> string = <fun> # concat "foo" "bar";; - : string = "foobar" # concat ?sep:(Some "what") "foo" "bar";; - : string = "foowhatbar"