0
votes

I am working on a contract evaluator for a contract DSL I am writing. The contract DSL is based on Simon Peyton Jones financial combinators paper. I am relatively new to Haskell and monads and I am having problems with the state monad. As you can see below evalAll2 is recursively called until End is reached. I have three variables in the record ContractSt that are updated when evalC is called, people is the number of parties to the contract(identified by a unique int), balance is amount of money in the contract and the owner is the a person who owns the contract. A contract is evaluated like this:

bettingContract :: Contract
bettingContract 
          = until (Date (2018,12,13)) 
                (cashIn 20 1 
                    (cashIn 20 2 
                        (time (Date (2018,12,15))
                            (pay 1 2 40 End)
                        End)
                    End)                            
                End)
            End

c1 = evalAll(bettingContract)

What I want the code to do is to output the Contract being evaluated, the "output" which is a message generated based the action of a particular and to show the values of the ContractSt after the contract has been evaluated. The main problem is that I get:

<interactive>:12:1: error:
    * No instance for (Show
                         (Control.Monad.Trans.State.Lazy.StateT
                            ContractSt
                            Data.Functor.Identity.Identity
                            ()))
        arising from a use of `print'

when I try and evaluate a contract. I understand that I have to use evalState to return the final result (which is what I want), and that I'm not trying to create an instance for of show for () but returning the final state along with the contract, and the output is where I'm having the most difficulty.

data ContractSt = ContractSt { 
people :: [Person], balance :: Money, owner :: Person } deriving (Show)

evalAll :: Contract -> (Contract, OP, State ContractSt ()
evalAll c = evalAll2 c [] initialState 

evalAll2 :: Contract -> OP -> State ContractSt () -> (Contract, OP, State 
ContractSt ()
evalAll2 c o s
    | c == End = (c, o, s)
    | otherwise = evalAll2 nc (o ++ no) ns
        where
            (nc, no,ns) = evalC c 
1
Is this the long form version of the question "How do I get the final Foo from a State Foo ()?" Or is it how to turn a tuple (a,b,x) into a tuple (a,b,c) given a function f :: x -> c? - that other guy
Yes more the latter, I want to return the final result of Contractst in a tuple with the contract currently being evaluated and the output message. - Noonanrick

1 Answers

0
votes

I didn't read through your motivation, but if your problem is how to transform the last element of a 3-tuple, you can easily write a function for that:

mapLast3 f (a,b,x) = (a, b, f x)

Here it is in a complete example, where a 3-tuple (Int, Double, State String ()) gets transformed into a (Int, Double, String) by running the computation with a hard coded initial state:

import Control.Monad.State

mapLast3 :: (x -> c) -> (a,b,x) -> (a,b,c)
mapLast3 f (a,b,x) = (a, b, f x)

myExecutor :: State String () -> String
myExecutor f = execState f "Hello"

execLast3 :: (a, b, State String ()) -> (a, b, String)
execLast3 = mapLast3 myExecutor

myStateFunction :: State String ()
myStateFunction = modify (++ " World")

myOriginalTuple :: (Int, Double, State String ())
myOriginalTuple = (42, 3.14, myStateFunction)

myFinalTuple :: (Int, Double, String)
myFinalTuple = execLast3 myOriginalTuple

main = print myFinalTuple

It will print (42,3.14,"Hello World")