Skip to content

Latest commit

 

History

History
57 lines (43 loc) · 2.17 KB

13.md

File metadata and controls

57 lines (43 loc) · 2.17 KB

Signalling failure

Many C function returns with a negative integer on failure. Different negative values might give information about the type of failure. This can not be solved with Maybe.

Either

data Either a b = Left a | Right b

The Either type is used to represent either a value of type a constructed with the Left data constructor or a value of type b constructed with Right. It is generally used to wrap the result of a computation that might fail. By convention the Left constructor is used to represent the failure case and the Right constructor is used for the success case. The wrapped values can be extracted with pattern matching.

Example

The following code contains a dummy algorithm, but demonstraits the idea well.

import Data.Maybe

data Message = Message {message :: Maybe String, signature :: Maybe String}

data MessageError = MissingMessage | MissingSignature | InvalidSignature deriving Show

validSignature :: Maybe String -> Maybe String -> Bool
validSignature content signature = let clen = length (fromJust content)
                                       slen = length (fromJust signature)
                                       lens = clen + slen
                                    in (1 == (lens `mod` 2))

getMessageContent :: Message -> Either MessageError String
getMessageContent (Message Nothing _) = Left MissingMessage
getMessageContent (Message _ Nothing) = Left MissingSignature
getMessageContent (Message content@(Just c) signature) = if validSignature content signature
                                                                  then Right c
                                                                  else Left InvalidSignature

report :: Message -> String
report msg = case getMessageContent msg of
               Left reason -> "Failed to get content: " ++ show reason
               Right content -> "The content is: " ++ content

Exercise

  • Implement the following functions.
data VelocityError = TimeIsNegative | TimeIsZero | LenIsNegative deriving Show
velocity :: (Integral a) => a -> a -> Either VelocityError a
velocityReport :: Show a => Either VelocityError a -> String