So the primary issue here is that guards need to be Boolean expression, i.e. they need to return a Boolean value, not an Either a b
.
You have two options: either you transform your functions into predicate, or you use Either a b
as a monad. The shortest way to get your code to “work” as a monad would be something like:
module Main where
import Daml.Script
import DA.List (head, tail)
import DA.Math (sqrt)
checkNumberOfSides: [Decimal] -> Either Text [Decimal]
checkNumberOfSides sides =
if ((length sides) /= 3) then
Left "Error"
else Right sides
checkIfSideIsZero: [Decimal] -> Int -> Either Text [Decimal]
checkIfSideIsZero sides idx =
if (head sides == 0.0) then
Left "Error"
else Right (tail sides)
{-
-- This doesn't work, because guards must be Boolean expressions.
triangleAreaWrong: [Decimal] -> Either Text [Decimal]
triangleAreaWrong sides = case sides of
_ | checkNumberOfSides sides -> Right sides
_ | checkIfSideIsZero sides 1 -> Right sides
_ | checkIfSideIsZero sides 2 -> Right sides
_ | checkIfSideIsZero sides 3 -> Right sides
_ -> Left "Error"
-}
triangleArea: [Decimal] -> Either Text Decimal
triangleArea sides = do
[a, b, c] <- checkNumberOfSides sides
_ <- checkIfSideIsZero sides 1
_ <- checkIfSideIsZero sides 2
_ <- checkIfSideIsZero sides 3
let s = (sum sides) / 2.0
return $ sqrt (s * (s -a) * (s - b) * (s -c))
setup : Script ()
setup = script do
debug $ triangleArea [1.0, 1.0, 1.0]
return ()
But that’s not very satisfying with all those _ <-
. We can do better. First, here’s what the guard-based approach could look like:
module Main where
import Daml.Script
import DA.Math (sqrt)
hasThreeSides: [Decimal] -> Bool
hasThreeSides sides = length sides == 3
noZeroSide: [Decimal] -> Bool
noZeroSide sides = 0.0 `notElem` sides
triangleArea: [Decimal] -> Either Text Decimal
triangleArea sides = case sides of
[a, b, c] | hasThreeSides sides && noZeroSide sides ->
let s = (sum sides) / 2.0
in return $ sqrt (s * (s -a) * (s - b) * (s -c))
_ -> Left "Error"
setup : Script ()
setup = script do
debug $ triangleArea [1.0, 1.0, 1.0]
return ()
It’s not clear to me what using guards and Either a b
adds in this case, but I think this illustrates nicely that this would not work as you want it to: you want to check that all the conditions match, whereas the guard syntax would offer one branch per condition.
If you want an example of how this could be constructed with Either a b
, we could try something like this:
module Main where
import Daml.Script
import DA.List((!!))
import DA.Math (sqrt)
nonZero: Decimal -> Either Text Decimal
nonZero 0.0 = Left "zero element"
nonZero x = Right x
asTriangle: [Decimal] -> Either Text (Decimal, Decimal, Decimal)
asTriangle sides =
if length sides /= 3 then
Left $ "Incorrect number of sides: " <> show (length sides)
else do
a <- nonZero $ sides !! 0
b <- nonZero $ sides !! 1
c <- nonZero $ sides !! 2
return (a, b, c)
triangleArea: [Decimal] -> Either Text Decimal
triangleArea sides = do
(a, b, c) <- asTriangle sides
let s = (sum sides) / 2.0
return $ sqrt (s * (s -a) * (s - b) * (s -c))
hasThreeSides: [Decimal] -> Bool
hasThreeSides sides = length sides == 3
noZeroSide: [Decimal] -> Bool
noZeroSide sides = 0.0 `notElem` sides
setup : Script ()
setup = script do
debug $ triangleArea [1.0, 1.0, 1.0]
return ()
Hopefully this clarifies things a bit. Otherwise, please don’t hesitate to ask more questions.