Home > Software engineering >  Change monad to myMonad in haskell
Change monad to myMonad in haskell

Time:01-01

I wrote a function that evaluates an expression.

import Data.Sequence as S (Seq(..), fromList)
import Data.Either (partitionEithers)

data HiFun =  HiFunList
  deriving (Show,Eq, Ord)  

data HiValue = HiValueNumber Rational
  | HiValueList (Seq HiValue)
  | HiValueFunction HiFun
  deriving (Show, Eq, Ord)

data HiExpr = HiExprValue HiValue
  | HiExprApply HiExpr [HiExpr]
  deriving Show

data HiError = HiErrorInvalidArgument
  | HiErrorInvalidFunction
  | HiErrorArityMismatch
  deriving Show

data HiAction =
    HiActionRead  FilePath
  | HiActionWrite FilePath ByteString
  | HiActionMkDir FilePath
  | HiActionChDir FilePath
  | HiActionCwd

data HiPermission =
    AllowRead
  | AllowWrite

data PermissionException =
  PermissionRequired HiPermission

instance Exception PermissionException

newtype HIO a = HIO { runHIO :: Set HiPermission -> IO a }

--eval :: Monad m => HiExpr -> m (Either HiError HiValue)
eval :: HiMonad m => HiExpr -> m (Either HiError HiValue) 
eval (HiExprValue a ) = return (Right a)
eval (HiExprApply (HiExprValue (HiValueNumber  _) ) _ ) = return (Left HiErrorInvalidFunction)
eval (HiExprApply exp args ) =  do
  op <- eval exp
  case op of 
    (Right (HiValueFunction HiFunList)) -> do 
      ll <- return (fmap (\x -> do a <- eval x ; a ) args) -- args :: [HiExpr]
      return (toL ll)


toL :: [(Either HiError HiValue)] -> (Either HiError HiValue)
toL xs  = let (ls, rs) = partitionEithers xs in
  if (length ls == 0)
  then (Right (HiValueList (fromList rs) ))
  else (Left HiErrorInvalidArgument)

I had to add

class Monad m => HiMonad m where
  runAction :: HiAction -> m HiValue

and change

eval :: Monad m => HiExpr -> m (Either HiError HiValue)

to

eval :: HiMonad m => HiExpr -> m (Either HiError HiValue)

And I got error

 • Could not deduce (HiMonad (Either HiError))
        arising from a use of ‘eval’
      from the context: HiMonad m
        bound by the type signature for:
                   eval :: forall (m :: * -> *).
                           HiMonad m =>
                           HiExpr -> m (Either HiError HiValue)
        at src\HW3\Evaluator.hs:19:1-57
    • In a stmt of a 'do' block: a <- eval x
      In the expression:
        do a <- eval x
           a
      In the first argument of ‘fmap’, namely
        ‘(\ x
            -> do a <- eval x
                  a)’
   |
28 |       ll <- return (fmap (\x -> do a <- eval x ; a ) args)
   |                                         ^^^^^^

As I could understand we don't have

instance HiMonad (Either HiError)

I think instance HiMonad (Either HiError) couldn't be written because of Monad m => HiMonad m Extra Text, Extra Text. Extra Text. Extra Text, Extra Text. Extra Text, Extra Text. Extra Text. Extra Text, Extra Text.

CodePudding user response:

I think I figured out what you're trying to do. You want to eval all of the arguments, within the same monad the outer eval is in, and then give that result to toL. To do that, replace this:

return (fmap (\x -> do a <- eval x ; a ) args)

with this:

traverse eval args

CodePudding user response:

Either HiError is already a monad. You don't need to add an additional Monad m layer (nor HiMonad m), just use it as is.

eval :: HiExpr -> Either HiError HiValue
eval (HiExprValue a) = return a
eval (HiExprApply (HiExprValue (HiValueNumber  _)) _) = Left HiErrorInvalidFunction
eval (HiExprApply exp args) =  do
  op <- eval exp
  case op of
    HiValueFunction HiFunList -> do
      argVals <- mapM eval args
      -- the next line mimics the existing code, but you probably want to do
      -- something to actually apply op to argVals here in your final version
      return (HiValueList (fromList argVals))
    HiValueFunction _ -> Left HiErrorArityMismatch -- or whatever...
    _ -> Left HiErrorInvalidFunction -- or whatever
  • Related