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?
Maybe you want this?
students =
Dict.get obj "students"
|> \studentsResult ->
when studentsResult is
Ok a -> readStudentsList a
_ -> Err "students not found in the object"
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"
If you can share the type of JsonData
and Student
I can make a more complete example
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")
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")
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
Is it more idiomatic to to use tag unions like this for errors rather than storing them in Strings?
Yes, I would say so. It's nice to be able to merge them and also exhaustively handle them too elsewhere in the program.
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]
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) […]
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
?
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
Result.try returns a new result, if the previous is an Err than it doesn't do anything.
Ahhhh
that compiles yep
what if I have an error in readStudentsList
? Is it possible to bubble up the errors from readStudentsList
That is what Result.try
will do. :smile:
Ahhhhh that makes a lot of sense thanks!!
Last updated: Jul 06 2025 at 12:14 UTC