How does this trick type-check? - haskell

Reading this blog post – https://www.haskellforall.com/2021/05/the-trick-to-avoid-deeply-nested-error.html – I realised I don't understand why the 'trick' actually works in this situation:
{-# LANGUAGE NamedFieldPuns #-}
import Text.Read (readMaybe)
data Person = Person { age :: Int, alive :: Bool } deriving (Show)
example :: String -> String -> Either String Person
example ageString aliveString = do
age <- case readMaybe ageString of
Nothing -> Left "Invalid age string"
Just age -> pure age
if age < 0
then Left "Negative age"
else pure ()
alive <- case readMaybe aliveString of
Nothing -> Left "Invalid alive string"
Just alive -> pure alive
pure Person{ age, alive }
Specifically I'm struggling to understand why this bit
if age < 0
then Left "Negative age"
else pure ()
type checks.
Left "Negative age" has a type of Either String b
while
pure () is of type Either a ()
Why does this work the way it does?
EDIT: I simplified and re-wrote the code into bind operations instead of do block, and then saw Will's edit to his already excellent answer:
{-# LANGUAGE NamedFieldPuns #-}
import Text.Read (readMaybe)
newtype Person = Person { age :: Int} deriving (Show)
example :: String -> Either String Person
example ageString =
getAge ageString
>>= (\age -> checkAge age
>>= (\()-> createPerson age))
getAge :: Read b => String -> Either [Char] b
getAge ageString = case readMaybe ageString of
Nothing -> Left "Invalid age string"
Just age -> pure age
checkAge :: (Ord a, Num a) => a -> Either [Char] ()
checkAge a = if a < 0
then Left "Negative age"
else pure ()
createPerson :: Applicative f => Int -> f Person
createPerson a = pure Person { age = a }
I think this makes the 'trick' of passing the () through binds much more visible - the values are taken from an outer scope, while Left indeed short-circuits the processing.

It typechecks because Either String b and Either a () unify successfully, with String ~ a and b ~ ():
Either String b
Either a ()
------------------
Either String () a ~ String, b ~ ()
It appears in the do block of type Either String Person, so it's OK, since it's the same monad, Either, with the same "error signal" type, String.
It appears in the middle of the do block, and there's no value "extraction". So it serves as a guard.
It goes like this: if it was Right y, then the do block's translation is
Right y >>= (\ _ -> .....)
and the computation continues inside ..... with the y value ignored. But if it was Left x, then
Left x >>= _ = Left x
according to the definition of >>= for Either. Crucially, the Left x on the right is not the same value as Left x on the left. The one on the left has type Either String (); the one on the right has type Either String Person indeed, as demanded by the return type of the do block overall.
The two Left x are two different values, each with its own specific type. The x :: String is the same, of course.

Related

How to pattern match on Constructors in Haskell?

I have a state machine where states are implemented using a sum type. Posting a simplified version here:
data State =
A { value :: Int }
| B { value :: Int }
| C { other :: String }
most of my functions are monadic consuming States and doing some actions based on the type. Something like (this code doesn't compile):
f :: State -> m ()
f st= case st of
s#(A | B) -> withValueAction (value s)
C -> return ()
I know that I could unroll constructors like:
f :: State -> m ()
f st= case st of
A v -> withValueAction v
B v -> withValueAction v
C _ -> return ()
But that's a lot of boilerplate and brittle to changes. If I change the parameters to the constructor I need to rewrite all case .. of in my codebase.
So how would you pattern match on a subset of constructors and access a shared element?
One way to implement this idiomatically is to use a slightly different value function:
value :: State -> Maybe Int
value (A v) = Just v
value (B v) = Just v
value _ = Nothing
Then you can write your case using a pattern guard like this:
f st | Just v <- value st -> withValueAction v
f C{} = return ()
f _ = error "This should never happen"
Or you can simplify this a bit further using view patterns and even more with pattern synonyms:
{-# LANGUAGE ViewPatterns, PatternSynonyms #-}
pattern V :: Int -> State
pattern V x <- (value -> Just v)
{-# COMPLETE V, C #-}
f (V x) = withValueAction x
f C{} = return ()
#Noughtmare's answer demonstrates how you can use view patterns to get the right "pattern matching syntax". To auto-generate the value function that selects a shared field from several constructors, you can use lens, though this kind of requires buying into the whole Lens ecosystem. After:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
import Control.Lens.TH
data State =
A { _value :: Int }
| B { _value :: Int }
| C { _other :: String }
makeLenses ''State
you will have a traversal value that can be used to access the partially shared field:
f :: (Monad m) => State -> m ()
f st = case st ^? value of
Just v -> withValueAction v
Nothing -> return ()
This is the solution I've picked at the end. My two main requirements were:
"Or" pattern matching over constructors
Selection of a subset of fields shared by the pattern match
As reported by #Noughtmare 1 is not possible at the moment https://github.com/ghc-proposals/ghc-proposals/pull/522.
Since for my problem the source of variability comes mostly from parameters in the constructors and not from the number of states, the solution I picked was to enable NamedFieldPuns extension, so the solution is something like:
f :: State -> m ()
f st= case st of
A {value} -> withValueAction value
B {value} -> withValueAction value
C {} -> return ()
It has some boilerplate enumerating constructors but at least it has none at the constructor parameters. I'll have a look at the view patterns maybe they are useful when the source of variability comes from the number of constructors and not the arguments.

Is there a compiler-extension for untagged union types in Haskell?

In some languages (#racket/typed, for example), the programmer can specify a union type without discriminating against it, for instance, the type (U Integer String) captures integers and strings, without tagging them (I Integer) (S String) in a data IntOrStringUnion = ... form or anything like that.
Is there a way to do the same in Haskell?
Either is what you're looking for... ish.
In Haskell terms, I'd describe what you're looking for as an anonymous sum type. By anonymous, I mean that it doesn't have a defined name (like something with a data declaration). By sum type, I mean a data type that can have one of several (distinguishable) types; a tagged union or such. (If you're not familiar with this terminology, try Wikipedia for starters.)
We have a well-known idiomatic anonymous product type, which is just a tuple. If you want to have both an Int and a String, you just smush them together with a comma: (Int, String). And tuples (seemingly) can go on forever--(Int, String, Double, Word), and you can pattern-match the same way. (There's a limit, but never mind.)
The well-known idiomatic anonymous sum type is Either, from Data.Either (and the Prelude):
data Either a b = Left a | Right b
deriving (Eq, Ord, Read, Show, Typeable)
It has some shortcomings, most prominently a Functor instance that favors Right in a way that's odd in this context. The problem is that chaining it introduces a lot of awkwardness: the type ends up like Either (Int (Either String (Either Double Word))). Pattern matching is even more awkward, as others have noted.
I just want to note that we can get closer to (what I understand to be) the Racket use case. From my extremely brief Googling, it looks like in Racket you can use functions like isNumber? to determine what type is actually in a given value of a union type. In Haskell, we usually do that with case analysis (pattern matching), but that's awkward with Either, and function using simple pattern-matching will likely end up hard-wired to a particular union type. We can do better.
IsNumber?
I'm going to write a function I think is an idiomatic Haskell stand-in for isNumber?. First, we don't like doing Boolean tests and then running functions that assume their result; instead, we tend to just convert to Maybe and go from there. So the function's type will end with -> Maybe Int. (Using Int as a stand-in for now.)
But what's on the left hand of the arrow? "Something that might be an Int -- or a String, or whatever other types we put in the union." Uh, okay. So it's going to be one of a number of types. That sounds like typeclass, so we'll put a constraint and a type variable on the left hand of the arrow: MightBeInt a => a -> Maybe Int. Okay, let's write out the class:
class MightBeInt a where
isInt :: a -> Maybe Int
fromInt :: Int -> a
Okay, now how do we write the instances? Well, we know if the first parameter to Either is Int, we're golden, so let's write that out. (Incidentally, if you want a nice exercise, only look at the instance ... where parts of these next three code blocks, and try to implement that class members yourself.)
instance MightBeInt (Either Int b) where
isInt (Left i) = Just i
isInt _ = Nothing
fromInt = Left
Fine. And ditto if Int is the second parameter:
instance MightBeInt (Either a Int) where
isInt (Right i) = Just i
isInt _ = Nothing
fromInt = Right
But what about Either String (Either Bool Int)? The trick is to recurse on the right hand type: if it's not Int, is it an instance of MightBeInt itself?
instance MightBeInt b => MightBeInt (Either a b) where
isInt (Right xs) = isInt xs
isInt _ = Nothing
fromInt = Right . fromInt
(Note that these all require FlexibleInstances and OverlappingInstances.) It took me a long time to get a feel for writing and reading these class instances; don't worry if this instance is surprising. The punch line is that we can now do this:
anInt1 :: Either Int String
anInt1 = fromInt 1
anInt2 :: Either String (Either Int Double)
anInt2 = fromInt 2
anInt3 :: Either String Int
anInt3 = fromInt 3
notAnInt :: Either String Int
notAnInt = Left "notint"
ghci> isInt anInt3
Just 3
ghci> isInt notAnInt
Nothing
Great!
Generalizing
Okay, but now do we need to write another type class for each type we want to look up? Nope! We can parameterize the class by the type we want to look up! It's a pretty mechanical translation; the only question is how to tell the compiler what type we're looking for, and that's where Proxy comes to the rescue. (If you don't want to install tagged or run base 4.7, just define data Proxy a = Proxy. It's nothing special, but you'll need PolyKinds.)
class MightBeA t a where
isA :: proxy t -> a -> Maybe t
fromA :: t -> a
instance MightBeA t t where
isA _ = Just
fromA = id
instance MightBeA t (Either t b) where
isA _ (Left i) = Just i
isA _ _ = Nothing
fromA = Left
instance MightBeA t b => MightBeA t (Either a b) where
isA p (Right xs) = isA p xs
isA _ _ = Nothing
fromA = Right . fromA
ghci> isA (Proxy :: Proxy Int) anInt3
Just 3
ghci> isA (Proxy :: Proxy String) notAnInt
Just "notint"
Now the usability situation is... better. The main thing we've lost, by the way, is the exhaustiveness checker.
Notational Parity With (U String Int Double)
For fun, in GHC 7.8 we can use DataKinds and TypeFamilies to eliminate the infix type constructors in favor of type-level lists. (In Haskell, you can't have one type constructor--like IO or Either--take a variable number of parameters, but a type-level list is just one parameter.) It's just a few lines, which I'm not really going to explain:
type family OneOf (as :: [*]) :: * where
OneOf '[] = Void
OneOf '[a] = a
OneOf (a ': as) = Either a (OneOf as)
Note that you'll need to import Data.Void. Now we can do this:
anInt4 :: OneOf '[Int, Double, Float, String]
anInt4 = fromInt 4
ghci> :kind! OneOf '[Int, Double, Float, String]
OneOf '[Int, Double, Float, String] :: *
= Either Int (Either Double (Either Float [Char]))
In other words, OneOf '[Int, Double, Float, String] is the same as Either Int (Either Double (Either Float [Char])).
You need some kind of tagging because you need to be able to check if a value is actually an Integer or a String to use it for anything. One way to alleviate having to create a custom ADT for every combination is to use a type such as
{-# LANGUAGE TypeOperators #-}
data a :+: b = L a | R b
infixr 6 :+:
returnsIntOrString :: Integer -> Integer :+: String
returnsIntOrString i
| i `rem` 2 == 0 = R "Even"
| otherwise = L (i * 2)
returnsOneOfThree :: Integer -> Integer :+: String :+: Bool
returnsOneOfThree i
| i `rem` 2 == 0 = (R . L) "Even"
| i `rem` 3 == 0 = (R . R) False
| otherwise = L (i * 2)

Haskell Monads Either

I have a little problem with Data Types in Haskell, I think I should post first some code to help to understand the problem
helper :: (MonadMask a, MonadIO a, Functor a) => Expr -> String -> a (Either InterpreterError Int)
helper x y = ( getEval ( mkCodeString x y ) )
-- Creates Code String
mkCodeString :: (Show a) => a -> String -> String
mkCodeString x y = unpack (replace (pack "Const ") (pack "") (replace (pack "\"") (pack "") (replace (pack "Add") (pack y) (pack (show x) ) ) ) )
-- Calculates String
getEval :: (MonadMask m, MonadIO m, Functor m) => [Char] -> m (Either InterpreterError Int)
getEval str = (runInterpreter (setImports ["Prelude"] >> interpret str (as ::Int)))
-- | A test expression.
testexpression1 :: Expr
testexpression1 = 3 + (4 + 5)
-- | A test expression.
testexpression2 :: Expr
testexpression2 = (3 + 4) + 5
-- | A test expression.
testexpression3 :: Expr
testexpression3 = 2 + 5 + 5
I use the helper Function like this "helper testexpression3 "(+)" and it returns me the value "Right 12" with the typ "Either InterpreterError Int", but I only want to have the "Int" value "12"
I tried the function -> "getValue (Right x) = x" but I dont get that Int value.
After some time of testing I think it is a problem with the Monads I've used.
If I test the typ of the helper function like this: ":t (helper testexpression1 "(+)")" I'll get that: "(... :: (Functor a, MonadIO a, MonadMask a) => a (Either InterpreterError Int)"
How can I make something like that working:
write "getValue (helper testexpression1 "(+)")" and get "12" :: Int
I'll know that the code makes no sence, but its a homework and I wanted to try some things with haskell.Hope you have some more Ideas than I am.
And Sorry for my bad English, I have began to learn English, but I am just starting and Thank you for every Idea and everything.
Edit, here is what was missing on code:
import Test.HUnit (runTestTT,Test(TestLabel,TestList),(~?))
import Data.Function (on)
import Language.Haskell.Interpreter -- Hint package
import Data.Text
import Data.Text.Encoding
import Data.ByteString (ByteString)
import Control.Monad.Catch
-- | A very simple data type for expressions.
data Expr = Const Int | Add Expr Expr deriving Show
-- | 'Expression' is an instance of 'Num'. You will get warnings because
-- many required methods are not implemented.
instance Num Expr where
fromInteger = Const . fromInteger
(+) = Add
-- | Equality of 'Expr's modulo associativity.
instance Eq Expr where
(==) x1 x2 = True --(helper x1 "(+)") == (helper x2 "(+)") && (helper x1 "(*)") == (helper x2 "(*)")
That functions are also in the file ... everything else I have in my file are some Testcases I have created for me.
helper textExpr "(+)" is not of type Either InterpreterError Int it is of type (MonadMask a, MonadIO a, Functor a) => a (Either InterpreterError Int). This later tyoe can be treated as if it was IO (Either InterpreterError Int) for our purposes.
In general something of type IO a (e.g. IO (Either InterpreterError Int)) doesn't contain, in the strictest sense, a value of type a, so you can't just extract a value willy-nilly. Something of type IO a is an action, that when performed, will produce a value of type a. Haskell only performs one action, the one called main. That said, it allows us to easily build larger actions out of smaller actions.
main = helper textExpr "(+)" >>= print
That operator there (>>=) is a monadic bind. For more information about monads in general, see You Could Have Invented Monads!. For an idea of how the IO Monad might be constructed see Free Monads for Less (Part 3 of 3): Yielding IO (under "Who Needs the RealWorld?") or Idris' implementation of IO -- but keep in mind that the IO Monad is opaque and abstract in Haskell; don't expect to be able to get an a value from an IO a value unless you are writing main (an application).

Errorhandling and monads?

I'm trying to understand how to apply the Maybe-idiom from Haskel.. I'm reading http://en.wikibooks.org/wiki/Haskell/Understanding_monads/Maybe which shows that a lookup in a dictionary may return a Maybe and that this value propates through the >>= operator.
The example from the URL:
If we then wanted to use the result from the governmental database lookup in a third lookup (say we want to look up their registration number to see if they owe any car tax), then we could extend our getRegistrationNumber function:
getTaxOwed :: String -- their name
-> Maybe Double -- the amount of tax they owe
getTaxOwed name =
lookup name phonebook >>=
(\number -> lookup number governmentalDatabase) >>=
(\registration -> lookup registration taxDatabase)
Or, using the do-block style:
getTaxOwed name = do
number <- lookup name phonebook
registration <- lookup number governmentalDatabase
lookup registration taxDatabase
Question:
How do I deal with error handling? I think most code will benefit from telling where things went wrong. Rather than just reporting "couldn't find John Doe in either phonebook or governmentalDatabase" it should report which ressource had problems.
You could use the monad instance for Either String, which is essentially defined as
instance Monad (Either String) where
fail msg = Left msg
return x = Right x
Left msg >>= k = Left msg
Right x >>= k = k x
(The actual definition is a bit more involved.)
If we then define dictionaries as pairs consisting of a label and a lookup table
type Dict a b = (String, [(a, b)])
phonebook' :: Dict String Int
phonebook' = ("phone book", phonebook)
governmentalDatabase' :: Dict Int Int
governmentalDatabase' = ("governmental database", governmentalDatabase)
taxDatabase' :: Dict Int Double
taxDatabase' = ("tax database", taxDatabase)
where phonebook, governmentalDatabase, and taxDatabase are as you had them defined before, we can use an alternative monadic lookup function that returns its result in the Either String-monad:
lookup' :: (Eq a, Show a) => a -> Dict a b -> Either String b
lookup' key (descr, table) = case lookup key table of
Nothing -> Left ("couldn't find " ++ show key ++ " in " ++ descr)
Just val -> Right val
Illustrating the power of monads, the only thing that now needs to change in your client function is the type signature:
getTaxOwed :: String -- their name
-> Either String Double -- either an error message
-- or the amount of tax they owe
getTaxOwed name = do
number <- lookup' name phonebook'
registration <- lookup' number governmentalDatabase'
lookup' registration taxDatabase'
Running this function on an unknown name gives:
> getTaxOwed "Joe"
Left "couldn't find \"Joe\" in phone book"
The Maybe data type has only the value "Nothing" for signaling an error. If you want to return a specific error message i suggest the data type "Either", which can return either a "Left a" or "Right a" value. Read more about how to use that at http://learnyouahaskell.com/for-a-few-monads-more#error

Is there a Haskell equivalent of OOP's abstract classes, using algebraic data types or polymorphism?

In Haskell, is it possible to write a function with a signature that can accept two different (although similar) data types, and operate differently depending on what type is passed in?
An example might make my question clearer. If I have a function named myFunction, and two types named MyTypeA and MyTypeB, can I define myFunction so that it can only accept data of type MyTypeA or MyTypeB as its first parameter?
type MyTypeA = (Int, Int, Char, Char)
type MyTypeB = ([Int], [Char])
myFunction :: MyTypeA_or_MyTypeB -> Char
myFunction constrainedToTypeA = something
myFunction constrainedToTypeB = somethingElse
In an OOP language, you could write what I'm trying to achieve like so:
public abstract class ConstrainedType {
}
public class MyTypeA extends ConstrainedType {
...various members...
}
public class MyTypeB extends ConstrainedType {
...various members...
}
...
public Char myFunction(ConstrainedType a) {
if (a TypeOf MyTypeA) {
return doStuffA();
}
else if (a TypeOf MyTypeB) {
return doStuffB();
}
}
I've been reading about algebraic data types and I think I need to define a Haskell type, but I'm not sure how to go about defining it so that it can store one type or another, and also how I use it in my own functions.
Yes, you are correct, you are looking for algebraic data types. There is a great tutorial on them at Learn You a Haskell.
For the record, the concept of an abstract class from OOP actually has three different translations into Haskell, and ADTs are just one. Here is a quick overview of the techniques.
Algebraic Data Types
Algebraic data types encode the pattern of an abstract class whose subclasses are known, and where functions check which particular instance the object is a member of by down-casting.
abstract class IntBox { }
class Empty : IntBox { }
class Full : IntBox {
int inside;
Full(int inside) { this.inside = inside; }
}
int Get(IntBox a) {
if (a is Empty) { return 0; }
if (a is Full) { return ((Full)a).inside; }
error("IntBox not of expected type");
}
Translates into:
data IntBox = Empty | Full Int
get :: IntBox -> Int
get Empty = 0
get (Full x) = x
Record of functions
This style does not allow down-casting, so the Get function above would not be expressible in this style. So here is something completely different.
abstract class Animal {
abstract string CatchPhrase();
virtual void Speak() { print(CatchPhrase()); }
}
class Cat : Animal {
override string CatchPhrase() { return "Meow"; }
}
class Dog : Animal {
override string CatchPhrase() { return "Woof"; }
override void Speak() { print("Rowwrlrw"); }
}
Its translation in Haskell doesn't map types into types. Animal is the only type, and Dog and Cat are squashed away into their constructor functions:
data Animal = Animal {
catchPhrase :: String,
speak :: IO ()
}
protoAnimal :: Animal
protoAnimal = Animal {
speak = putStrLn (catchPhrase protoAnimal)
}
cat :: Animal
cat = protoAnimal { catchPhrase = "Meow" }
dog :: Animal
dog = protoAnimal { catchPhrase = "Woof", speak = putStrLn "Rowwrlrw" }
There are a few different permutations of this basic concept. The invariant is that the abstract type is a record type where the methods are the fields of the record.
EDIT: There is a good discussion in the comments on some of the subtleties of this approach, including a bug in the above code.
Typeclasses
This is my least favorite encoding of OO ideas. It is comfortable to OO programmers because it uses familiar words and maps types to types. But the record of functions approach above tends to be easier to work with when things get complicated.
I'll encode the Animal example again:
class Animal a where
catchPhrase :: a -> String
speak :: a -> IO ()
speak a = putStrLn (catchPhrase a)
data Cat = Cat
instance Animal Cat where
catchPhrase Cat = "Meow"
data Dog = Dog
instance Animal Dog where
catchPhrase Dog = "Woof"
speak Dog = putStrLn "Rowwrlrw"
This looks nice, doesn't it? The difficulty comes when you realize that even though it looks like OO, it doesn't really work like OO. You might want to have a list of Animals, but the best you can do right now is Animal a => [a], a list of homogeneous animals, eg. a list of only Cats or only Dogs. Then you need to make this wrapper type:
{-# LANGUAGE ExistentialQuantification #-}
data AnyAnimal = forall a. Animal a => AnyAnimal a
instance Animal AnyAnimal where
catchPhrase (AnyAnimal a) = catchPhrase a
speak (AnyAnimal a) = speak a
And then [AnyAnimal] is what you want for your list of animals. However, it turns out that AnyAnimal exposes exactly the same information about itself as the Animal record in the second example, we've just gone about it in a roundabout way. Thus why I don't consider typeclasses to be a very good encoding of OO.
And thus concludes this week's edition of Way Too Much Information!
It sounds like you might want to read up on typeclasses.
Consider this example using TypeClasses.
We define a c++-like "abstract class" MVC based on three types (note MultiParamTypeClasses): tState tAction tReaction in order to
define a key function tState -> tAction -> (tState, tReaction) (when an action is applied to the state, you get a new state and a reaction.
The typeclass has
three "c++ abstract" functions, and some more defined on the "abstract" ones. The "abstract" functions will be defined when and instance MVC is needed.
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, NoMonomorphismRestriction #-}
-- -------------------------------------------------------------------------------
class MVC tState tAction tReaction | tState -> tAction tReaction where
changeState :: tState -> tAction -> tState -- get a new state given the current state and an action ("abstract")
whatReaction :: tState -> tReaction -- get the reaction given a new state ("abstract")
view :: (tState, tReaction) -> IO () -- show a state and reaction pair ("abstract")
-- get a new state and a reaction given an state and an action (defined using previous functions)
runModel :: tState -> tAction -> (tState, tReaction)
runModel s a = let
ns = (changeState s a)
r = (whatReaction ns)
in (ns, r)
-- get a new state given the current state and an action, calling 'view' in the middle (defined using previous functions)
run :: tState -> tAction -> IO tState
run s a = do
let (s', r) = runModel s a
view (s', r)
return s'
-- get a new state given the current state and a function 'getAction' that provides actions from "the user" (defined using previous functions)
control :: tState -> IO (Maybe tAction) -> IO tState
control s getAction = do
ma <- getAction
case ma of
Nothing -> return s
Just a -> do
ns <- run s a
control ns getAction
-- -------------------------------------------------------------------------------
-- concrete instance for MVC, where
-- tState=Int tAction=Char ('u' 'd') tReaction=Char ('z' 'p' 'n')
-- Define here the "abstract" functions
instance MVC Int Char Char where
changeState i c
| c == 'u' = i+1 -- up: add 1 to state
| c == 'd' = i-1 -- down: add -1 to state
| otherwise = i -- no change in state
whatReaction i
| i == 0 = 'z' -- reaction is zero if state is 0
| i < 0 = 'n' -- reaction is negative if state < 0
| otherwise = 'p' -- reaction is positive if state > 0
view (s, r) = do
putStrLn $ "view: state=" ++ (show s) ++ " reaction=" ++ (show r) ++ "\n"
--
-- define here the function "asking the user"
getAChar :: IO (Maybe Char) -- return (Just a char) or Nothing when 'x' (exit) is typed
getAChar = do
putStrLn "?"
str <- getLine
putStrLn ""
let c = str !! 0
case c of
'x' -> return Nothing
_ -> return (Just c)
-- --------------------------------------------------------------------------------------------
-- --------------------------------------------------------------------------------------------
-- call 'control' giving the initial state and the "input from the user" function
finalState = control 0 getAChar :: IO Int
--
main = do
s <- finalState
print s

Resources