我把一些F#代码ocaml的,我看到很多这样的管道运营商的用途<|
, 例如:
let printPeg expr =
printfn "%s" <| pegToString expr
该<|
运营商显然是定义为只是:
# let ( <| ) a b = a b ;;
val ( <| ) : ('a -> 'b) -> 'a -> 'b = <fun>
我不知道为什么他们懒得定义和使用该运营商在F#中,它只是使他们能够避免将在这样的括号?:
let printPeg expr =
Printf.printf "%s" ( pegToString expr )
据我所知,这将是上面的OCaml的F#代码的转换,是否正确?
另外,我将如何实现F#的<<
和>>
在ocaml的运营商?
(在|>
操作者似乎简单地是: let ( |> ) ab = ba ;;
)
直接从F#来源 :
let inline (|>) x f = f x
let inline (||>) (x1,x2) f = f x1 x2
let inline (|||>) (x1,x2,x3) f = f x1 x2 x3
let inline (<|) f x = f x
let inline (<||) f (x1,x2) = f x1 x2
let inline (<|||) f (x1,x2,x3) = f x1 x2 x3
let inline (>>) f g x = g(f x)
let inline (<<) f g x = f(g x)
为什么他们懒得定义和F#中使用该运营商,它只是使他们能够避免将在括号?
这是因为编程的功能性的方式呈现,通过功能链线程的值。 相比:
let f1 str server =
str
|> parseUserName
|> getUserByName server
|> validateLogin <| DateTime.Now
let f2 str server =
validateLogin(getUserByName(server, (parseUserName str)), DateTime.Now)
在第一个片段中,我们清楚地看到,与价值发生的一切。 读第二个,我们要通过所有的括号弄清楚发生了什么事情。
本文关于函数组合似乎是相关的。
所以,是的,在有规律的生活,它主要是关于括号。 但同时,管道运营商密切相关的部分功能应用和编码的自由点式。 见编程是“毫无意义的” ,例如。
管道|>
和功能组成>>
<<
运营商可以当它们被传递到更高级别的功能,如产生另一个有趣的效果在这里 。
OCaml Batteries supports these operators, but for reasons of precedence, associativity and other syntactic quirks (like Camlp4) it uses different symbols. Which particular symbols to use has just been settled recently, there are some changes. See: Batteries API:
val (|>) : 'a -> ('a -> 'b) -> 'b
Function application. x |> f is equivalent to f x.
val ( **> ) : ('a -> 'b) -> 'a -> 'b
Function application. f **> x is equivalent to f x.
Note The name of this operator is not written in stone. It is bound to change soon.
val (|-) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c
Function composition. f |- g is fun x -> g (f x). This is also equivalent to applying <** twice.
val (-|) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
Function composition. f -| g is fun x -> f (g x). Mathematically, this is operator o.
But Batteries trunk provides:
val ( @@ ) : ('a -> 'b) -> 'a -> 'b
Function application. [f @@ x] is equivalent to [f x].
val ( % ) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
Function composition: the mathematical [o] operator.
val ( |> ) : 'a -> ('a -> 'b) -> 'b
The "pipe": function application. [x |> f] is equivalent to [f x].
val ( %> ) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c
Piping function composition. [f %> g] is [fun x -> g (f x)].
我不知道为什么他们懒得去定义和F#中使用该运营商,它只是使他们能够避免将在这样的括号?
非常好的问题。 (你指的是与特定运营商<|
是相当无用的IME。 它可以让你避免在极少数情况下括号,但更普遍的是通过更多的运营商拖动语法复杂化并使其更难经验不足的F#程序员(其中有现在很多)来理解你的代码。 所以,我已经停止使用它。
该|>
运营商是更为有用的,但仅仅是因为它有助于F#正确地推断类型的情况下OCaml中不会有问题。 例如,这里是一些OCaml的:
List.map (fun o -> o#foo) os
的直接等同于F#失败,因为类型o
不能之前阅读其推断foo
属性所以惯用的解决方案是使用重写这样的代码|>
所以F#可以推断出的类型o
之前foo
用于:
os |> List.map (fun o -> o.foo)
我很少使用其他运营商( <<
和>>
),因为他们也语法复杂化。 我也喜欢在很多运营商的拉解析器组合库。
Bytebuster给的例子很有意思:
let f1 str server =
str
|> parseUserName
|> getUserByName server
|> validateLogin <| DateTime.Now
我会写这样的:
let f2 str server =
let userName = parseUserName str
let user = getUserByName server userName
validateLogin user DateTime.Now
有在我的代码没有括号。 所以他们出现在调试器,我可以检查它们和智能能给我型倒退,当我将鼠标悬停在他们的临时我有名字。 这些特性对于生产代码,非专家F#程序员将保持有价值的。