Stream: beginners

Topic: nested match on result


view this post on Zulip Monica (Jul 01 2024 at 22:03):

Can anyone explain where I'm going wrong with the following:

Students : List Student
Res : Result Students [Err Str]
readStudents : JsonData -> Res
readStudents= \json ->
    when json is
        Object obj ->
            students = Dict.get obj "students"
                when students is
                    Ok a -> readStudentsList a
                    _ -> Err "students not found in the object"
        _ -> Err "Expected Json Object"

readStudentsList : JsonData -> Result Students [Err Str]
...

on my second branch of my second pattern match, I'm getting an error of
Something is off with the 2nd branch of this
when expression:
// code above
This Err tag application has the type:
[
Err Str,
Ok Students,
]
But the type annotation on readStudents says it should be:
Result Students [Err Str]

Is this not how I should be chaining together functions which return Results of the same type?

view this post on Zulip Luke Boswell (Jul 01 2024 at 23:21):

Maybe you want this?

students =
    Dict.get obj "students"
    |> \studentsResult ->
        when studentsResult is
            Ok a -> readStudentsList a
                _ -> Err "students not found in the object"

view this post on Zulip Luke Boswell (Jul 01 2024 at 23:23):

Something like this might be easier to follow

students =
    Dict.get obj "students"
    |> Result.map readStudentsList
    |> Result.mapErr \_ -> Err "students not found in the object"

view this post on Zulip Luke Boswell (Jul 01 2024 at 23:26):

If you can share the type of JsonData and Student I can make a more complete example

view this post on Zulip Luke Boswell (Jul 01 2024 at 23:28):

Ok so this code works, but I've made some assumptions

emptyStudents : Students
emptyStudents = []

readStudents : JsonData -> Result Students [Err Str]
readStudents = \json ->
    when json is

        Object obj ->

            Dict.get obj "students"
            |> Result.map \_ -> emptyStudents
            |> Result.mapErr \_ -> Err "students not found in the object"

        _ ->
            Err (Err "Expected Json Object")

view this post on Zulip Luke Boswell (Jul 01 2024 at 23:30):

I think one possible point of confusion is that you have named the Tag in your error union as Err which is also the name of the tag in a Result, so to return a valid Result _ [Err Str] you need to use Err (Err "my msg")

view this post on Zulip Luke Boswell (Jul 01 2024 at 23:31):

If you change the error to something more descriptive like

readStudents : JsonData -> Result Students [StudentsNotFoundInObj, ExepectedJsonOjbect]
readStudents = \json ->
    when json is

        Object obj ->

            Dict.get obj "students"
            |> Result.map \_ -> emptyStudents
            |> Result.mapErr \_ -> StudentsNotFoundInObj

        _ ->
            Err ExepectedJsonOjbect

view this post on Zulip Monica (Jul 02 2024 at 08:05):

Is it more idiomatic to to use tag unions like this for errors rather than storing them in Strings?

view this post on Zulip Luke Boswell (Jul 02 2024 at 08:08):

Yes, I would say so. It's nice to be able to merge them and also exhaustively handle them too elsewhere in the program.

view this post on Zulip Monica (Jul 02 2024 at 08:10):

This is where I've gotten to with your help:

Student : {
    name : Str,
    modules : List (Module)
}

Module : {
    name : Str,
    credits : I64
}

JsonData : [
    String Str,
    Number U64,
    Null,
    Object (Dict Str JsonData),
    Arr (List JsonData),
]

readStudents : JsonData -> Result (List Student) [StudentsNotFoundInObj, ExepectedJsonOjbect, EmptyListOfStudents, ExpectedJsonArray]
readStudents= \json ->
    when json is
        Object obj ->
            Dict.get obj "students"
            |> Result.map \_ -> readStudentsList
            |> Result.mapErr \_ -> StudentsNotFoundInObj
        _ -> Err ExepectedJsonOjbect

readStudentsList : JsonData -> Result (List Student) [EmptyListOfStudents, ExpectedJsonArray]

view this post on Zulip Monica (Jul 02 2024 at 08:11):

But I am confused about the error message I am getting

This when expression produces:

    Result (JsonData -> Result (List Student) [
        EmptyListOfStudents,
        ExpectedJsonArray,
    ]) […]

But the type annotation on readStudents says it should be:

    Result (List Student) […]

view this post on Zulip Monica (Jul 02 2024 at 08:11):

Is this because my call to readStudentsList also returns a result? And I need to flatten them in order to either get my Ok or my Err?

view this post on Zulip Luke Boswell (Jul 02 2024 at 08:13):

Dict.get obj "students" will return a result, you are mapping the Ok value into another function readStudentsList which also returns a result. That is why you have nested results. Also you you have no actually provided a value to call readStudentsList, so that is why it shows as a Fn.

Try using |> Result.try readStudentsList instead

view this post on Zulip Luke Boswell (Jul 02 2024 at 08:14):

Result.try returns a new result, if the previous is an Err than it doesn't do anything.

view this post on Zulip Monica (Jul 02 2024 at 08:15):

Ahhhh

view this post on Zulip Monica (Jul 02 2024 at 08:15):

that compiles yep

view this post on Zulip Monica (Jul 02 2024 at 08:16):

what if I have an error in readStudentsList? Is it possible to bubble up the errors from readStudentsList

view this post on Zulip Luke Boswell (Jul 02 2024 at 08:21):

That is what Result.try will do. :smile:

view this post on Zulip Monica (Jul 02 2024 at 08:31):

Ahhhhh that makes a lot of sense thanks!!


Last updated: Jul 06 2025 at 12:14 UTC