Stream: ideas

Topic: ! in pipe


view this post on Zulip Anton (May 21 2024 at 14:38):

This works:

args = Arg.list!

arg =
    List.get args 1
    |> Result.withDefault "No command line args provided."

But this doesn't:

arg =
    Arg.list!
    |> List.get args 1
    |> Result.withDefault "No command line args provided."

I personally think this would be very handy and I believe users would also expect this to work.
It seems feasible to make the desugaring smarter/adaptive so that this does work.
I'd love to hear your thoughts :)

view this post on Zulip Richard Feldman (May 21 2024 at 16:11):

oh yeah it’s supposed to work! I think it may just not have been implemented yet :big_smile:

view this post on Zulip Anton (May 21 2024 at 16:15):

#6765

view this post on Zulip Luke Boswell (May 22 2024 at 01:33):

It should be working I think, I would expect it to desugar to the same as

arg =
    Task.await Arg.list \answer ->
        answer
        |> List.get args 1
        |> Result.withDefault "No command line args provided."

view this post on Zulip Luke Boswell (May 22 2024 at 04:17):

The following works as expected

app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }

import pf.Stdout
import pf.Arg
import pf.Task exposing [Task]

main =
    arg =
        (Arg.list!)
            |> List.get 1
            |> Result.withDefault "No command line args provided."

    Stdout.line arg

view this post on Zulip Luke Boswell (May 22 2024 at 04:19):

So there are two interesting things here

  1. We need the Parens to unwrap it before passing into the pipeline... maybe this is not the desired behaviour and we should fix that? @Richard Feldman
  2. The parser requires the indentation after the ! to continue parsing the expression. @Joshua Warner

view this post on Zulip Joshua Warner (May 22 2024 at 04:44):

Requiring indentation there seems wrong… or at least unnecessary

view this post on Zulip Joshua Warner (May 22 2024 at 04:45):

Probably just requires a little fiddling with min_indent

view this post on Zulip Kiryl Dziamura (May 22 2024 at 08:56):

also works

    arg = (Arg.list!)
        |> List.get 1
        |> Result.withDefault "No command line args provided."

doesn't work but fails with a different error

    arg = Arg.list!
        |> List.get 1
        |> Result.withDefault "No command line args provided."
This 1st argument to this function has an unexpected type:

 8│>      arg = Arg.list!
 9│>          |> List.get 1
10│>          |> Result.withDefault "No command line args provided."

This withDefault call produces:

    Str

But this function needs its 1st argument to be:

    InternalTask.Task a b

Looks like the same logic as in Luke's snippets above

view this post on Zulip Richard Feldman (May 22 2024 at 11:25):

Luke Boswell said:

So there are two interesting things here

  1. We need the Parens to unwrap it before passing into the pipeline... maybe this is not the desired behaviour and we should fix that? Richard Feldman
  2. The parser requires the indentation after the ! to continue parsing the expression. Joshua Warner

Yeah, we shouldn't need the parens or the indentation! :smiley:

view this post on Zulip Kiryl Dziamura (May 22 2024 at 14:54):

May I take this issue? @Luke Boswell would be happy to have some guidance here. I'm struggling with debugging and not sure when exactly it fails - it must be during desugaring of either pizza or task_await, or maybe it's even upstream. Any tips?

view this post on Zulip Anton (May 22 2024 at 14:56):

Thanks for helping out @Kiryl Dziamura, I've assigned you to the issue :)

view this post on Zulip Luke Boswell (May 22 2024 at 15:00):

@Kiryl Dziamura I'd be interested in pairing to show you what I know about the parser and canonicalisation.

I think an evening my time would probably be best. The earliest I could do is , would that work for you?

Also happy to point to files before then if your keen to get started. :grinning:

view this post on Zulip Kiryl Dziamura (May 22 2024 at 15:16):

It would be great! I'll prepare some questions about the codebase then. Added to my calendar

Also happy to point to files before then if your keen to get started

yes please, I'll do a little digging :)

view this post on Zulip Joshua Warner (May 25 2024 at 03:17):

Curious if you ended up getting any further / figuring it out?

view this post on Zulip Kiryl Dziamura (May 25 2024 at 07:00):

So there are at least two problems:

indentation during parsing: it expects

a!
    |> b

instead of

a!
|> b

And then desugaring: it transforms

a = b! |> c
d a

into

a = Task.await x -> c x
d a

instead of

Task.await x ->
    a = c x
    d a

Upd: I was investigating top level declarations, which is not applicable here.

view this post on Zulip Kiryl Dziamura (May 25 2024 at 07:13):

I expected suffix doesn’t affect indentation at all. Why a specific indentation rule was introduced?

Probably it's caused by the fact that the exclamation mark works both for a task value and functions that return a task value:

a! --> Task.await a x -> x
a! b --> Task.await (a b) x -> x

view this post on Zulip Luke Boswell (May 25 2024 at 07:34):

I wonder if this might only be a parser problem. The |> operator gets completely desugared beforehand.

view this post on Zulip Kiryl Dziamura (May 25 2024 at 07:49):

Might be! I’ll take a closer look today

view this post on Zulip Kiryl Dziamura (May 25 2024 at 16:06):

It's BinOps of Pizzas where the first item is TaskAwaitBang after parsing. So likely it's desugaring

view this post on Zulip Kiryl Dziamura (May 25 2024 at 17:19):

From what I understand, currently, it works this way:

a! |> b -> b a! -> Task.await (b a) \...

The second transformation is incorrect. But b (a!) works as expected, which explains why parens helped in the Luke’s snippet above

view this post on Zulip Kiryl Dziamura (May 27 2024 at 16:25):

The fix for the bang in args (consequently for the pipe logic) is ready
https://github.com/roc-lang/roc/pull/6777

The second part would be for indentation but I’m not sure what’s the current convention. From what I saw in the code, it intentionally expects +1 indentation here. However, it's not clear to me why the bang requires any changes to indentation at all


Last updated: Jun 16 2026 at 16:19 UTC