Stream: beginners

Topic: Echo program


view this post on Zulip JRI98 (Dec 13 2023 at 15:22):

Hello. I am trying to build a program that reads lines from Stdin, changes them and writes to Stdout.
Right now it looks like

app "hello"
    packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" }
    imports [pf.Task.{ Task }, pf.Stdin, pf.Stdout, pf.Stderr]
    provides [main] to pf

loop : Task {} I32
loop =
    line <- Stdin.line |> Task.await
    when line is
        End ->
            Stderr.line "EOF"

        Input s ->
            {} <- Stdout.line (inputToOutput s) |> Task.await
            loop

inputToOutput : Str -> Str
inputToOutput = \input ->
    input

main : Task {} I32
main = loop

Eventually the inputToOutput function will get more complex, but right now I'm hitting a compiler error:

thread 'main' panicked at 'Error in alias analysis: error in module ModName("UserApp"), function definition FuncName("\x12\x00\x00\x00\x02\x00\x00\x00\xb5\x94\rioj\xd2="), definition of value binding ValueId(3): could not find func in module ModName("UserApp") with name FuncName(")\x00\x00\x00\x04\x00\x00\x00\xb5\x94\rioj\xd2=")', crates/compiler/gen_llvm/src/llvm/build.rs:5713:19

This seems to be the same as https://github.com/roc-lang/roc/issues/5701. I tried changing the code to circumvent the compiler error, but got no luck. Any tips? :smile:

view this post on Zulip Brendan Hansknecht (Dec 13 2023 at 15:59):

Try writing it with Task.loop

view this post on Zulip JRI98 (Dec 13 2023 at 16:13):

Thank you so much :grinning_face_with_smiling_eyes:
For anyone reading, the working program looks like

app "hello"
    packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.0/bkGby8jb0tmZYsy2hg1E_B2QrCgcSTxdUlHtETwm5m4.tar.br" }
    imports [pf.Task.{ Task }, pf.Stdin, pf.Stdout, pf.Stderr]
    provides [main] to pf

loop : Task {} I32
loop =
    Task.loop
        {}
        (\state ->
            line <- Stdin.line |> Task.await
            when line is
                End ->
                    {} <- Stderr.line "EOF" |> Task.await
                    Task.ok (Done state)

                Input s ->
                    {} <- Stdout.line (inputToOutput s) |> Task.await
                    Task.ok (Step state)
        )

inputToOutput : Str -> Str
inputToOutput = \input ->
    input

main : Task {} I32
main = loop

view this post on Zulip Brendan Hansknecht (Dec 13 2023 at 16:17):

As a note, long term both should work just fine I'm pretty sure, but our underlying effect primitive is kinda naive currently. We have plans to switch out the implementation, and I think that would fix this.


Last updated: Jul 05 2025 at 12:14 UTC