Symbolic mathematics in Haskell

import Control.Monad (liftM2)

infixl 4 :+:, :-: 
infixl 5 :*:, :/:

data Expr a  = Const a 
         | (Expr a) :+: (Expr a) 
         | (Expr a) :-: (Expr a)
         | (Expr a) :*: (Expr a)
         | (Expr a) :/: (Expr a)
         deriving (Show, Eq)

evalExpr (Const a) = a 
evalExpr (a :+: b) = liftM2 (+) (evalExpr a) (evalExpr b)
evalExpr (a :-: b) = liftM2 (-) (evalExpr a) (evalExpr b)
evalExpr (a :*: b) = liftM2 (*) (evalExpr a) (evalExpr b)
evalExpr (a :/: b) = if (evalExpr b) == 0 
        then Nothing 
         else liftM2 (/) (evalExpr a) (evalExpr b)

This is my symbolic representation of mathematics and evaluation function. I have a problem with my limited knowledge of monads, and perhaps this problem arises because I want to return a value of nothing if there is division by zero in my evaluation function. For many reasons, when I try to run evalExpr (Const 3)or something more complex, it fails at runtime. Is something missing?

+4
source share
1 answer

Version, I think you want:

import Control.Monad (liftM2)

infixl 4 :+:, :-: 
infixl 5 :*:, :/:

data Expr a  = Const a 
         | (Expr a) :+: (Expr a) 
         | (Expr a) :-: (Expr a)
         | (Expr a) :*: (Expr a)
         | (Expr a) :/: (Expr a)
         deriving (Show, Eq)

evalExpr :: (Eq a, Num a, Fractional a) => (Expr a) -> Maybe a
evalExpr (Const a) = return a 
evalExpr (a :+: b) = liftM2 (+) (evalExpr a) (evalExpr b)
evalExpr (a :-: b) = liftM2 (-) (evalExpr a) (evalExpr b)
evalExpr (a :*: b) = liftM2 (*) (evalExpr a) (evalExpr b)
evalExpr (a :/: b) = if (evalExpr b) == return 0
        then Nothing 
        else liftM2 (/) (evalExpr a) (evalExpr b)

Changes use the correct monadic (in this case Maybe) type in the case Const( return ainstead of a), and when you check the value 0 ( if (evalExpr b) == return 0rather than if (evalExpr b) == 0).

( , Just, return, Maybe, .)

evalExpr, , . liftM2 Haskell , , , , . , , , Const ==, .

<$> <*> liftM2, :

import Control.Applicative ((<$>), (<*>))

...

evalExpr :: (Eq a, Num a, Fractional a) => (Expr a) -> Maybe a
evalExpr (Const a) = return a 
evalExpr (a :+: b) = (+) <$> (evalExpr a) <*> (evalExpr b)
evalExpr (a :-: b) = (-) <$> (evalExpr a) <*> (evalExpr b)
evalExpr (a :*: b) = (*) <$> (evalExpr a) <*> (evalExpr b)
evalExpr (a :/: b) = if (evalExpr b) == return 0
        then Nothing 
        else (/) <$> (evalExpr a) <*> (evalExpr b)

, triad ,

triad <$> arg1 <*> arg2 <*> arg3

. .

@gallais . , , , :

evalExpr :: (Eq a, Num a, Fractional a) => (Expr a) -> Maybe a
evalExpr (Const a) = return a 
evalExpr (a :+: b) = (+) <$> (evalExpr a) <*> (evalExpr b)
evalExpr (a :-: b) = (-) <$> (evalExpr a) <*> (evalExpr b)
evalExpr (a :*: b) = (*) <$> (evalExpr a) <*> (evalExpr b)
evalExpr (a :/: b) = (/) <$> (evalExpr a) <*> (failOn 0 $ evalExpr b)

failOn x a = case a of
    Just x -> Nothing
    _      -> a

, MonadZero :

...
evalExpr (a :/: b) = (/) <$> (evalExpr a) <*> (failOn (==0) $ evalExpr b)

failOn f a = do
    b <- fmap f a
    if b then mzero else a

, , guard, when unless, . .

+3

All Articles