The Either Monad

class hymn.types.either.Either

the either monad

computation with two possibilities

bind(self, f)

the bind operation of Either

apply function to the value if and only if this is a Right.

plus(self, other)
from_value(cls, value)

wrap value in an Either monad

return a Right if the value is evaluated as true. Left otherwise.

class hymn.types.either.Left

left of Either

class hymn.types.either.Right

right of Either

hymn.types.either.is_left(m)

return True if m is a Left

hymn.types.either.is_right(m)

return True if m is a Right

hymn.types.either.either(handle_left, handle_right m)

case analysis for Either

apply either handle-left or handle-right to m depending on the type of it, raise TypeError if m is not an Either

@hymn.types.either.failsafe(func)

decorator to turn func into monadic function of Either monad

hymn.types.either.to_either()

alias of from_value()

Hy Specific API

either-m

alias of Either

->either

alias of from_value()

left?

alias of is_left()

right?

alias of is_right()

Reader Macro

| [f]

turn f into monadic function with failsafe()

Examples

Comparison

Either are comparable if the wrapped values are comparable. Right is greater than Left in any case.

=> (import hymn.types.either [Left Right])
=> (> (Right 2) (Right 1))
True
=> (< (Left 2) (Left 1))
False
=> (> (Left 2) (Right 1))
False

Do Notation

=> (import hymn.types.either [Left Right])
=> (require hymn.macros [do-monad-return])
=> (do-monad-return [a (Right 1) b (Right 2)] (+ a b))
Right(3)
=> (do-monad-return [a (Left 1) b (Right 2)] (+ a b))
Left(1)

Do Notation with :when

=> (import hymn.types.either [either-m])
=> (require hymn.macros [do-monad-with])
=> (defn safe-div [a b]
...    (do-monad-with either-m [:when (not (= 0 b))] (/ a b)))
=> (safe-div 1 2)
Right(0.5)
=> (safe-div 1 0)
Left('unknown error')

Operations

Use ->either to create an Either from a value

=> (import hymn.types.either [->either])
=> (->either 42)
Right(42)
=> (->either None)
Left(None)

Use left?() and right?() to test the type

=> (import hymn.types.either [Left Right left? right?])
=> (right? (Right 42))
True
=> (left? (Left None))
True

either() applies function to value in the monad depending on the type

=> (import hymn.types.either [Left Right either])
=> (either print (fn [x] (+ x 1)) (Left 1))
1
=> (either print (fn [x] (+ x 1)) (Right 1))
2

failsafe() turns function into monadic one

=> (import hymn.types.either [failsafe])
=> (defn [failsafe] add1 [n] (+ 1 (int n)))
=> (add1 "41")
Right(42)
=> (add1 "nan")
Left(ValueError("invalid literal for int() with base 10: 'nan'"))
=> (import hy.pyops [/])
=> (setv safe-div (failsafe /))
=> (safe-div 1 2)
Right(0.5)
=> (safe-div 1 0)
Left(ZeroDivisionError('division by zero'))

Reader Macro

=> (require hymn.types.either :readers [|])
=> (#| int "42")
Right(42)
=> (#| int "nan")
Left(ValueError("invalid literal for int() with base 10: 'nan'"))
=> (import hy.pyops [/])
=> (setv safe-div #| /)
=> (safe-div 1 2)
Right(0.5)
=> (safe-div 1 0)
Left(ZeroDivisionError('division by zero'))