Search code examples
syntaxreasonbucklescript

Compile error using fast pipe operator after pipe last in ReasonML


The way that the "fast pipe" operator is compared to the "pipe last" in many places implies that they are drop-in replacements for each other. Want to send a value in as the last parameter to a function? Use pipe last (|>). Want to send it as the first parameter? Use fast pipe (once upon a time |., now deprecated in favour of ->).

So you'd be forgiven for thinking, as I did until earlier today, that the following code would get you the first match out of the regular expression match:

Js.String.match([%re "/(\\w+:)*(\\w+)/i"], "int:id")
|> Belt.Option.getExn
-> Array.get(1)

But you'd be wrong (again, as I was earlier today...)

Instead, the compiler emits the following warning:

We've found a bug for you!
OCaml preview 3:10-27
This has type:
  'a option -> 'a
But somewhere wanted:
  'b array

See this sandbox. What gives?


Solution

  • Looks like they screwed up the precedence of -> so that it's actually interpreted as

    Js.String.match([%re "/(\\w+:)*(\\w+)/i"], "int:id")
    |> (Belt.Option.getExn->Array.get(1));
    

    With the operators inlined:

    Array.get(Belt.Option.getExn, 1, Js.String.match([%re "/(\\w+:)*(\\w+)/i"], "int:id"));
    

    or with the partial application more explicit, since Reason's syntax is a bit confusing with regards to currying:

    let f = Array.get(Belt.Option.getExn, 1);
    f(Js.String.match([%re "/(\\w+:)*(\\w+)/i"], "int:id"));
    

    Replacing -> with |. works. As does replacing the |> with |..

    I'd consider this a bug in Reason, but would in any case advise against using "fast pipe" at all since it invites a lot of confusion for very little benefit.