将F#管道运算符(<|,>>,<<)转换为OCaml

ane*_*eal 8 f# ocaml inline

我正在将一些F#代码转换为OCaml,我看到了这个管道运算符的很多用途<|,例如:

let printPeg expr =
    printfn "%s" <| pegToString expr
Run Code Online (Sandbox Code Playgroud)

<|运营商显然是定义为只是:

# let ( <| ) a b = a b ;;
val ( <| ) : ('a -> 'b) -> 'a -> 'b = <fun>
Run Code Online (Sandbox Code Playgroud)

我想知道为什么他们懒得在F#中定义和使用这个操作符,是不是就这样他们可以避免像这样放入一些parens?:

let printPeg expr =
    Printf.printf "%s" ( pegToString expr )
Run Code Online (Sandbox Code Playgroud)

据我所知,这将是上面的F#代码转换为OCaml,对吗?

另外,我如何在Ocaml中实现F#<<>>运算符?

(该|>操作似乎仅仅是:let ( |> ) a b = b a ;;)

byt*_*ter 15

为什么他们懒得在F#中定义和使用这个操作符,是不是因为他们可以避免放入parens?

这是因为编程的功能性假设通过一系列函数来线程化一个值.相比:

let f1 str server =
    str
    |> parseUserName
    |> getUserByName server
    |> validateLogin <| DateTime.Now

let f2 str server =
    validateLogin(getUserByName(server, (parseUserName str)), DateTime.Now)
Run Code Online (Sandbox Code Playgroud)

在第一个片段中,我们清楚地看到了价值所发生的一切.阅读第二篇文章,我们必须仔细检查所有正在发生的事情.

这篇关于功能构成的文章似乎是相关的.

所以,是的,在正常的生活中,它主要是关于parens.而且,管道运营商与部分功能应用和无点编码风格密切相关.例如,请参阅编程"无意义".

管道|>和函数组合>> <<运算符在传递给更高级别的函数时可以产生另一个有趣的效果,就像这里一样.

  • @JonHarrop请仔细阅读.我故意制作了`date` a**second**参数来证明`<|`运算符的有用性. (6认同)

ild*_*arn 12

直接来自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)
Run Code Online (Sandbox Code Playgroud)


luk*_*afi 10

OCaml Batteries支持这些运算符,但出于优先级,关联性和其他语法怪癖(如Camlp4)的原因,它使用不同的符号.最近使用的特定符号刚刚解决,有一些变化.请参阅:电池API:

val (|>) : 'a -> ('a -> 'b) -> 'b
Run Code Online (Sandbox Code Playgroud)

功能应用.x |> f相当于f x.

val ( **> ) : ('a -> 'b) -> 'a -> 'b
Run Code Online (Sandbox Code Playgroud)

功能应用.f**> x相当于f x.注意此运算符的名称不是一成不变的.它必将很快改变.

val (|-) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c
Run Code Online (Sandbox Code Playgroud)

功能构成.f | - g很有趣x - > g(fx).这相当于应用<**两次.

val (-|) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
Run Code Online (Sandbox Code Playgroud)

功能构成.f - | g很有趣x - > f(gx).在数学上,这是运算符o.

电池后备箱提供:

val ( @@ ) : ('a -> 'b) -> 'a -> 'b
Run Code Online (Sandbox Code Playgroud)

功能应用.[f @@ x]相当于[fx].

val ( % ) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
Run Code Online (Sandbox Code Playgroud)

函数组成:数学[o]运算符.

val ( |> ) : 'a -> ('a -> 'b) -> 'b
Run Code Online (Sandbox Code Playgroud)

"管道":功能应用程序.[x |> f]相当于[fx].

val ( %> ) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c
Run Code Online (Sandbox Code Playgroud)

管道功能组成.[f%> g]是[有趣的x - > g(fx)].


Jon*_*rop 6

我想知道为什么他们懒得在F#中定义和使用这个操作符,是不是就这样他们可以避免像这样放入这样的parens?

好问题.您所指的特定运算符(<|)是非常无用的IME.它允许您在极少数情况下避免使用括号,但更一般地说,它通过拖动更多运算符使语法复杂化,并使经验较少的F#程序员(现在有很多)更难理解您的代码.所以我已经停止使用它了.

|>运营商更加有用的,但仅仅是因为它有助于F#正确地推断类型的情况下OCaml中不会有问题.例如,这里有一些OCaml:

List.map (fun o -> o#foo) os
Run Code Online (Sandbox Code Playgroud)

直接等价在F#中失败,因为在o读取其foo属性之前无法推断出类型,因此惯用解决方案是使用|>这样重写代码,因此F#可以推断出使用o之前的类型foo:

os |> List.map (fun o -> o.foo)
Run Code Online (Sandbox Code Playgroud)

我很少使用其他运算符(<<>>),因为它们也使语法复杂化.我也不喜欢解析大量运算符的解析器组合库.

Bytebuster的例子很有意思:

let f1 str server =
  str
  |> parseUserName
  |> getUserByName server
  |> validateLogin <| DateTime.Now
Run Code Online (Sandbox Code Playgroud)

我会这样写:

let f2 str server =
  let userName = parseUserName str
  let user = getUserByName server userName
  validateLogin user DateTime.Now
Run Code Online (Sandbox Code Playgroud)

我的代码中没有括号.我的临时工具有名称,所以它们出现在调试器中,我可以检查它们,当我将鼠标悬停在它们上面时,Intellisense可以给我类型回归.这些特性对于非专业F#程序员将要维护的生产代码很有价值.

  • +1请继续在答案中提供额外信息.有很多次我问一个问题,因为我需要知道一些事情,我问的不是我需要的,因为我不确切知道我需要什么.如果我这样做,我不会问很多问题.带有类型推断的|>的用处花了我一些时间来理解,John在这里免费注释.读者可以随意忽略它.这不是反对bytebuster :)而是说我仍然有SO的精神问题.是放鱼还是教人钓鱼的景象? (5认同)