de-loke
de-loke

Reputation: 61

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.

Upvotes: 1

Views: 380

Answers (1)

Boyd Stephen Smith Jr.
Boyd Stephen Smith Jr.

Reputation: 3202

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).

Upvotes: 1

Related Questions