Here’s an example (first in Haskell then in Go), lets say you have some types/functions:
type Possible a = Either String a
data User = User { name :: String, age :: Int }
validateName :: String -> Possible String
validateAge :: Int -> Possible Int
then you can make
mkValidUser :: String-> Int -> Possible User
mkValidUser name age = do
validatedName ← validateName name
validatedAge ← validateAge age
pure $ User validatedName validatedAge
for some reason <- in lemmy shows up as <- inside code blocks, so I used the left arrow unicode in the above instead
in Go you’d have these
(no Possible type alias, Go can’t do generic type aliases yet, there’s an open issue for it)
In the Haskell, the fact that Either is a monad is saving you from a lot of boilerplate. You don’t have to explicitly handle the Left/error case, if any of the Eithers end up being a Left value then it’ll correctly “short-circuit” and the function will evaluate to that Left value.
Without using the fact that it’s a functor/monad (e.g you have no access to fmap/>>=/do syntax), you’d end up with code that has a similar amount of boilerplate to the Go code (notice we have to handle each Left case now):
mkValidUser :: String ->Int-> Possible User
mkValidUser name age =case (validatedName name, validateAge age) of
(Left nameErr, _) =>Left nameErr
(_, Left ageErr) =>Left ageErr
(Right validatedName, Right validatedAge) =>Right $ User validatedName validatedAge
Here’s an example (first in Haskell then in Go), lets say you have some types/functions:
then you can make
mkValidUser :: String -> Int -> Possible User mkValidUser name age = do validatedName ← validateName name validatedAge ← validateAge age pure $ User validatedName validatedAge
for some reason <- in lemmy shows up as
<-
inside code blocks, so I used the left arrow unicode in the above insteadin Go you’d have these
Possible
type alias, Go can’t do generic type aliases yet, there’s an open issue for it)and with them you’d make:
func mkValidUser(name string, age int) (*User, error) { validatedName, err = validateName(name) if err != nil { return nil, err } validatedAge, err = validateAge(age) if err != nil { return nil, err } return User(Name: validatedName, Age: validatedAge), nil }
In the Haskell, the fact that
Either
is a monad is saving you from a lot of boilerplate. You don’t have to explicitly handle theLeft
/error case, if any of theEither
s end up being aLeft
value then it’ll correctly “short-circuit” and the function will evaluate to thatLeft
value.Without using the fact that it’s a functor/monad (e.g you have no access to fmap/>>=/do syntax), you’d end up with code that has a similar amount of boilerplate to the Go code (notice we have to handle each
Left
case now):mkValidUser :: String -> Int -> Possible User mkValidUser name age = case (validatedName name, validateAge age) of (Left nameErr, _) => Left nameErr (_, Left ageErr) => Left ageErr (Right validatedName, Right validatedAge) => Right $ User validatedName validatedAge