如何在OCaml中无需fun声明,用|>反向应用运算符构造函数?
你遇到的错误本质是运算符逻辑与函数类型不匹配:|>是把左侧表达式的值作为参数传给右侧函数,is_attr |> not等价于not is_attr——但is_attr是string -> bool类型的函数,而not需要的是bool类型的参数,自然触发类型错误。
要实现你想要的“无匿名函数包裹”写法,核心是函数组合:把is_attr和not拼接成一个新的string -> bool函数,有两种常用方式:
1. 使用标准库Fun.compose(OCaml 4.12+)
OCaml 4.12及以上版本的标准库Fun模块提供了compose函数,定义为let compose f g x = f (g x),正好可以把not和is_attr组合成目标函数:
let parse_test_header (header : string list) : string * (string list) = let is_attr (line : string) : bool = ':' == get line 0 in let test_name = List.find (Fun.compose not is_attr) header in let test_attrs = List.filter is_attr header in (test_name, test_attrs)
这里Fun.compose not is_attr完全等价于你原来的fun line -> line |> is_attr |> not,逻辑一致且无需手动写匿名函数。
2. 自定义反向组合运算符
如果你觉得Fun.compose的参数顺序(先外层函数、后内层函数)不够直观,可以自己定义一个反向组合运算符,贴合你想要的链式风格:
(* 定义反向组合:f >> g 等价于 fun x -> g (f x) *) let (>>) f g x = g (f x) let parse_test_header (header : string list) : string * (string list) = let is_attr (line : string) : bool = ':' == get line 0 in let test_name = List.find (is_attr >> not) header in let test_attrs = List.filter is_attr header in (test_name, test_attrs)
is_attr >> not的写法和你最初设想的is_attr |> not几乎一致,逻辑上就是把is_attr的输出传给not,完全符合直觉。
补充:原写法行不通的核心原因
|>是值传递运算符,line |> is_attr |> not是把line这个字符串值传给is_attr得到布尔值,再把布尔值传给not;但is_attr |> not是直接把is_attr这个函数传给not,类型不匹配是必然的。函数组合需要的是把两个函数“拼接”成新函数,而不是传递值。
内容的提问来源于stack exchange,提问作者user2852699

