G-d willing
Hello,
how can I have 2 different values in a case switch to do the same thing
For example,
data IntValues
= FirstInt
| SecondInt
| ThirdInt
returnIntValue : IntValues -> Int
returnIntValue val = case val of
FirstInt -> 0
SecondInt -> 1
ThirdInt -> 1
How can I not duplicate the code when I am having SecondInt
or ThirdInt
. I tried using ,
and ||
but it didn’t work
The other option is to do it the following way:
returnIntValue val = case val of
FirstInt -> 0
val | val == SecondInt || val = ThirdInt -> 1
But this code is having an error Pattern match(es) are non-exhaustive
.
You can use guards, either in the case expression or directly at the function level:
module Guards where
import DA.Assert
import Daml.Script
data IntValues
= FirstInt
| SecondInt
| ThirdInt
| FourthInt
deriving (Eq, Show)
returnIntValue : IntValues -> Int
returnIntValue val = case val of
x | x == FirstInt || x == SecondInt -> 1
| x == ThirdInt || x == FourthInt -> 2
| otherwise -> error "impossible"
returnIntValue' : IntValues -> Int
returnIntValue' val
| val == FirstInt || val == SecondInt = 1
| val == ThirdInt || val == FourthInt = 2
| otherwise = error "impossible"
test : Script ()
test = script do
2 === returnIntValue ThirdInt
2 === returnIntValue' ThirdInt
return ()
They are mentioned only briefly in our docs here as an additional topic, but work exactly as in Haskell.
1 Like
G-d willing
Thanks @bernhard for your solution. Is there a way Daml can know that all pattern matches are exhaustive without using the otherwise
?
The Daml compiler only knows about exhaustiveness when you use pattern matches. When you use guards like above, the compiler is not smart enough to see that the expression is always true.
There are some ways to avoid guards here though: First you can use a wildcard match for the last two cases. That’s not a general solution but it works well if you just want to match on “everything else”.
returnIntValue : IntValues -> Int
returnIntValue val = case val of
FirstInt -> 0
_ -> 1
One downside of that is that you won’t get a compile error if you add a new case so it might silently do the wrong thing. You won’t get a compile error with guards either but at least you get a runtime error.
The other option is that you keep it as separate matches but you factor out the code and use it on the right hand side. In this example this looks a bit weird since you just have 1
there but if the code is more complex, this can often be a good solution. Note that the code you factor out could also be a function that takes arguments which is useful if you’re matching on constructors that take arguments.
returnIntValue : IntValues -> Int
returnIntValue val = case val of
FirstInt -> 0
SecondInt -> secondAndThird
ThirdInt -> secondAndThird
where secondAndThird = 1
2 Likes