I'm taking a compilers class, and I decided to do it in haskell, but I'm having a hard time setting up the ast. My issue is that I have an Atom class and an Expr class and one instance of the Expr can be an Atom, but when the Expr is immediately an Atom it has an issue. Here is the example:
data Atom -- cannot be reduced farther
= Const Int -- int is value
| Var String -- string is name
deriving (Show) -- So we can print it
data Expr -- add input and the like
= Add Expr Expr -- add is two exprs
| USub Expr -- negation
| Input -- call to input
| Atomic Atom -- or an atomic
deriving (Show) -- So we can print it
data Statement
= Print Expr
| Discard Expr
| Assign String Expr
deriving (Show) -- So we can print it
main = do
let test5 = Print (Const 2)
putStrLn $ show test5
The compiler fails on the Print (Const 2) because it expected an Expr. Is there a fix to this, and is there better vocabular for expressing this problem?
Const 2 is an Atom, but Print takes an Expr as an argument. Luckily, every Atom can be made into an Expr with the Atomic constructor. So:
main = do
let test5 = Print (Atomic (Const 2))
print test5
Related
Is there a way to control programmatically the set of values to use in an elements call within an arbitrary definition? I want to be able to generate an arbitrary variable reference as part of a random expression, but the set of variables identifiers to choose from should be configurable.
As example, imagine the following data type:
data Expr = Num Int
| Var String
| BinOp Op Expr Expr
data Op = Add | Sub | Mul | Div deriving (Eq, Ord, Enum)
And then I want to define an arbitrary instance for this type that would look something like this:
instance Arbitrary Op where
arbitrary = elements [Add .. ]
instance Arbitrary Expr where
arbitrary = oneof [ fmap Num arbitrary
, arbitraryBinOp
, fmap Var (elements varNames)
]
arbitraryBinOp = do (op, e0, e1) <- arbitrary
return (BinOp op e0 e1)
Now the tricky thing is the "varNames" part. Conceptually I would like to be able to do something like this:
do args <- getArgs
tests <- generate $ vectorOf 10 ((arbitrary args)::Gen Expr)
But obviously I can't propagate that args-vector down through the arbitrary calls as "arbitrary" does not take such an argument...
Arbitrary is really only a convenience when the generator does not require any context. If you need to parameterize your generators, you can define them as regular functions, and QuickCheck has combinators to use such explicit generators instead of Arbitrary instances.
genExpr :: [String] -> Gen Expr
genExpr varNames =
oneof [ fmap Num arbitrary
, arbitraryBinOp
, fmap Var (elements varNames)
]
main :: IO ()
main = do
args <- getArgs
tests <- generate $ vectorOf 10 (genExpr args)
{- do stuff -}
return ()
First i want to say I'm a newbie in Haskell. Here's my problem:
For a school project I need to be able to parse and interprate and execute a fucntion call. This call needs to be able to execute a function already defined in haskell.
Parsing the call works, but i have no idea how to execute the function because the amount of arguments and type is unkown.
Here is how i represent my data
type Name = String
type Cond = Expr
data Expr
= Num Int
| Boolean Bool
| BinOp Op Expr Expr
| Var Name
deriving (Eq, Ord, Show)
data Stmnt
= Call Name [Expr]
| If Cond [Stmnt] [Stmnt]
| While Cond [Stmnt]
| VarDef Name Expr
deriving (Eq, Ord, Show)
This is a part of my interpeter. And it is with the implementation of funcall that I need help.
data Value = FineInt Int
| FineBool Bool
| FineFun ([Value] -> Value)
-- The enviroment keeps track of variables in the program
type Env = [(Name,Value)]
-- A state that takes an enviroment
type StEnv = State Env
evalstm :: Stmnt -> StEnv ()
evalstm (Call name exprs) = funcall name exprs
-- funcall name exprs = ?
How can i print a value that is a non string type to console? The type is below.
data Expr = Var String | Con Bool | Uno Unop Expr | Duo Duop Expr Expr | List [Expr]
deriving Show
I have a list of the above type values and i would like to print them to screen each on a separate line( not the classic list view). Thanks
Just use print on each element of your list:
mapM' print exprs
I'm currently learning Haskell and trying to understand how typeclasses are evaluated, and how let and where work. This code runs fine:
{-# LANGUAGE FlexibleInstances #-}
class Expr a where
literal :: Integer -> a
instance Expr Integer where
literal = id
instance Expr [Integer] where
literal i = [i]
coerceInteger :: Integer -> Integer
coerceInteger = id
main = print $ coerceInteger (literal 100) : literal 100 -- Prints [100,100]
but changing the main function to
main = print $ coerceInteger expr : expr
where expr = literal 200
causes a compiler error:
Couldn't match expected type `[Integer]' with actual type `Integer'
In the second argument of `(:)', namely `expr'
In the second argument of `($)', namely `coerceInteger expr : expr'
In the expression: print $ coerceInteger expr : expr
I'm guessing this is because in the first main method the literal 100 is evaluated twice, whereas in the second example literal 200 is only evaluated once and so the compiler is forced to choose a type.
How can I factor out that code to avoid repeating myself, without causing this error? I tried using let expr = literal 300 in ... but ran into the same issue.
The problem is that the literal 200 is interpreted differently in the two different contexts with your first example. Think of it as
((:) :: a -> [a] -> [a])
((coerceInteger :: Integer -> Integer) (literal 100 :: Expr a => a))
(literal 100 :: Expr a => a)
Just based off the types, the compiler determines that the first literal 100 must have type Integer because it's being passed to coerceInteger, since it has to take a value of type Integer. This also sets the type of (:) to now be Integer -> [Integer] -> [Integer], implying that the last literal 100 has to have type [Integer].
In the second example, you're saying that both of them have the same value, and therefore the same type, which is impossible because the second must be a list for (:) to type check.
This actually occurs because of the dreaded Monomorphism restriction. You can fix this problem in two ways: One, turn off the monomorphism restriction with {-# LANGUAGE NoMonomorphismRestriction #-}, or you can provide an explicit type to expr that keeps it generalized:
main :: IO ()
main = print $ coerceInteger expr : expr
where
expr :: Expr a => a
expr = literal 100
Either of these approaches work, and whatever you decide to do I would recommend always providing type signatures to help avoid these problems.
In fact, once you add the type signature you can even do things like
main :: IO ()
main = print $ coerceInteger expr : expr : expr : expr : expr : expr
where
expr :: Expr a => a
expr = literal 100
without any problems, this will print out [100, 100, 100, 100, 100, 100]. The initial coerceInteger is needed though, because otherwise the compiler won't know what to instantiate it as and therefore won't have a Show instance for print.
In the process of writing an interpreter in Haskell for a separate, simple programming language - I find myself butting my head against a wall as I learn typing in Haskell.
I have two custom data types
data Expr
= Var Var
| NumE Int
| NilE
| ConsE Expr Expr
| Plus Expr Expr
| Minus Expr Expr
| Times Expr Expr
| Div Expr Expr
| Equal Expr Expr
| Less Expr Expr
| Greater Expr Expr
| Not Expr
| Isnum Expr
| And Expr Expr
| Or Expr Expr
| Head Expr
| Tail Expr
| Call String
deriving (Show, Read)
data Val = Num Int | Nil | Cons Val Val
deriving (Eq, Show, Read)
and I'm starting to write the cases for interpreting these options, with the function interpret_expr
interpret_expr :: Vars -> Expr -> Val
interpret_expr vars#(Vars a b c d) (NumE integer) = integer
but this COMPLAINS that it couldn't match expected type 'Val' with actual type 'Int' in the expression 'integer'. But say I change it to something silly like
interpret_expr :: Vars -> Expr -> Val
interpret_expr vars#(Vars a b c d) (NumE 'a') = 'a'
it then complains at 'a' that it can't match expected type 'Int' with actual type 'Char'. NOW IT WANTS AN INT?????? I really don't know what to say, I really thought it would be as simple as providing NumE with a variable it could figure is an integer. What am I doing wrong?
In the first case you are returning an Int from a function you declared to return a Val. From your definition of Val it looks like you probably want to return Num integer here.
In the second case the problem is in the pattern matching. (NumE 'a') is an error because NumE is defined as NumE Int, so it must be followed by an Int, not a Char.