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 = ?
Related
I am trying to build an interpreter for a C-like language in Haskell. I have so far written and combined small monadic parsers following this paper, hence so far I can generate an AST representation of a program. I defined the abstract syntax as follows:
data LangType = TypeReal | TypeInt | TypeBool | TypeString deriving (Show)
type Id = String
data AddOp = Plus | Minus | Or deriving (Show)
data RelOp = LT | GT | LTE | GTE | NEq | Eq deriving (Show)
data MultOp = Mult | Div | And deriving (Show)
data UnOp = UnMinus | UnNot deriving (Show)
data BinOp = Rel RelOp | Mul MultOp | Add AddOp deriving (Show)
data AST = Program [Statement] deriving (Show)
data Block = StatsBlock [Statement] deriving (Show)
data Statement = VariableDecl Id LangType Expression
| Assignment Id Expression
| PrintStatement Expression
| IfStatement Expression Block Block
| WhileStatement Expression Block
| ReturnStatement Expression
| FunctionDecl Id LangType FormalParams Block
| BlockStatement Block
deriving (Show)
data Expression = RealLiteral Double
| IntLiteral Int
| BoolLiteral Bool
| StringLiteral String
| Unary UnOp Expression
| Binary BinOp Expression Expression
| FuncCall Id [Expression]
| Var Id
deriving (Show)
data FormalParams = IdentifierType [(Id, LangType)] deriving (Show)
I have yet to type-check my AST and build the interpreter to evaluate expressions and execute statements. My questions are the following:
Does the abstract syntax make sense/can it be improved? In particular, I've been running into a recurring problem. In the EBNF of this language I'm trying to interpret, a WhileStatement consists of an Expression (which I have no problem with) and a Block, which in the EBNF happens to be a Statement just like WhileStatement, and so I cannot refer to Block from my WhileStatement. I've worked around this by defining a separate data type Block (as is shown in the above code), but am not sure if this is the best way. I'm finding defining data types quite confusing.
Since I have to type-check my AST and evaluate/execute, do I implement these separately or can I define some function which does them both at the same time?
Any general tips on how I should go about type-checking and interpreting the language would also be greatly appreciated. Since the language has variable and function declarations, I am thinking of implementing some sort of symbol table, although again I am struggling with defining the type for this. So far I've tried
import qualified Data.Map as M
data Value = RealLit Double | IntLit Int | BoolLit Bool | StringLit String | Func [FormalParams] String
deriving (Show)
type TermEnv = M.Map String Value
but I'm unsure whether I should be using my LangType from before.
Addressing your question in the comments about how to proceed with type checking and evaluation.
If you don't have to do inference or polymorphism, type checking is pretty simple. Also type checking and evaluation mirror each other pretty closely in these conditions.
Begin by defining a monad with the features you need. For a type checker, you will need
A type environment, i.e. a Reader(Map Id LangType) component, to keep track of the types of local variables.
An error ability, e.g. ExceptString.
So you could define a monad like
type TypeEnv = Map.Map Id LangType
type TC = ReaderT TypeEnv (Except String)
And then your typechecker function would look like:
typeCheck :: AST -> TC ()
(We return () because there is nothing interesting to be gained from the typechecking process besides knowing whether the program passed.)
This will be largely structurally inductive, e.g.
typeCheck (Program stmt) = -- typecheckStmt each statement*
typeCheckStmt :: Statement -> TC ()
typeCheckStmt (VariableDecl v type defn) = ...
typeCheckStmt (Assignment v exp) = do
Just t <- asks (Map.lookup v)
t' <- typeCheckExp exp
when (t /= t') $ throwError "Types do not match"
...
-- Return the type of a composite expression to use elsewhere
typeCheckExp :: Expression -> TC LangType
...
There will be a bit of finesse required to make sure that variable declarations in a list of statements can be seen by later statements in the same list. I will leave that as a puzzle. (Hint: see the local function to provide an updated environment within a scope.)
Evaluation is a similar story. You're correct that you need a type of run-time values. Without some cleverness that you are probably not ready for (and is of questionable utility even if you were) there is not really a way to use LangType in Value, so you're on the right track.
You will need a monad that supports keeping track of the values of variables and the ability to do whatever else your language needs. To start I recommend
type Eval = StateT (Map Id Value) IO
and proceed structurally as before. There will again be some finesse required when handling variable scopes and shadowing, and you may need to change the environment type or mess with your Value type a bit to accommodate these subtleties, but thinking through these problems is important. Start simple, don't try to implement typechecking and evaluation for your whole language at once.
I'm trying to create a data type class that contains a list:
data Test = [Int] deriving(Show)
But Haskell can't parse the constructor. What am i doing wrong here and how can I best achieve what I'm trying to do?
An Answer
You need to include a constructor, which you haven't done.
data Test = Test [Int]
Consider reviewing Haskell's several type declarations, their use, and their syntax.
Haskell Type Declarations
data
Allows declaration of zero or more constructors each with zero or more fields.
newtype
Allows declaration of one constructor with one field. This field is strict.
type
Allows creation of a type alias which can be textually interchanged with the type to the right of the equals at any use.
constructor
Allows creation of a value of the declared type. Also allows decomposition of values to obtain the individual fields (via pattern matching)
Examples
data
data Options = OptionA Int | OptionB Integer | OptionC PuppyAges
^ ^ ^ ^ ^ ^ ^
| | Field | | | |
type Constructor | | Constructor |
Constructor Field Field
deriving (Show)
myPuppies = OptionB 1234
newtype
newtype PuppyAges = AgeList [Int] deriving (Show)
myPuppies :: PuppyAges
myPuppies = AgeList [1,2,3,4]
Because the types (PuppyAges) and the constructors (AgeList) are in different namespaces people can and often do use the same name for each, such as newtype X = X [Int].
type
type IntList = [Int]
thisIsThat :: IntList -> [Int]
thisIsThat x = x
constructors (more)
option_is_a_puppy_age :: Options -> Bool
option_is_a_puppy_age (OptionC _) = True
option_is_a_puppy_age () = False
option_has_field_of_value :: Options -> Int -> Bool
option_has_field_of_value (OptionA a) x = x == a
option_has_field_of_value (OptionB b) x = fromIntegral x == b
option_has_field_of_value (OptionC (AgeList cs)) x = x `elem` cs
increment_option_a :: Options -> Options
increment_option_a (OptionA a) = OptionA (a+1)
increment_option_a x = x
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
I want write a haskell program to implement a simple imperative language based on its denotational semantics.
I use GHCi, version 8.4.2 on windows.
I encountered some issue when implementing function and procedure abstraction described below.
let me describe it. I call it IMP.
First, I define abstract syntax.
IMP only accept integer. and identifier will be string.
type Numeral = Int
type Ident = String
data Command =
Skip
| Assign (Ident, Expression)
| Letin (Declaration, Command )
| Cmdcmd (Command, Command )
| Ifthen (Expression, Command, Command)
| Whiledo (Expression, Command )
| IdentifierC ( ActualParameter )
data Expression =
Num Numeral
| False_
| True_
| Notexp Expression
| Id Ident
| Sumof (Expression, Expression)
| Subof (Expression, Expression)
| Prodof (Expression, Expression)
| Less (Expression, Expression)
| Leten (Declaration, Expression)
| IdentifierE ( ActualParameter )
deriving Show
type ActualParameter = Expression
data FormalParameter = Constfp Identifier
data Declaration =
Constdef (Ident, Expression)
| Vardef (Ident, TypeDef )
| Func Identifier ( FormalParameter ) ~ Expression
| Proce Identifier ( FormalParameter ) ~ Command
deriving Show
data TypeDef =
Bool | Int
deriving Show
brief explanation:
in Command, Skip will do nothing.
Assign will give value of the Expression to the Ident.
Letin will declare some variable in command.
Cmdcmd will run 2 commands sequentially.
Ifthen is conditional command, if first expression is evaluated to true, then run first command, second command otherwise.
Whiledo is loop.
IdentifierC ( ActualParameter ): IdentifierC denotes some function in the local environment. this ActualParameter is some expression with some value. this command jus call this function on the specified value.
in Expression, from top to down are:
numeral
bool false
bool true
negate of expression
get value of the Ident from the local environment.
sum 2 expressions
substract 2 expressions
product of 2
<
declare some variable in expression
IdentifierE ( ActualParameter ) IdentifierE denotes some function in the local environment. this ActualParameter is some expression with some value. this command jus call this function on the specified value. finally got a new value as the result of this expression.
then is Semantic Domains
type Integer = Int
type Boolean = Bool
type Location = Int
type Function = Argument -> Store -> Value
type Procedure = Argument -> Store -> Store
-- store would be snapshot of the memory.
data Value = IntValue Int
| TruthValue Bool
deriving (Eq, Show)
-- first class value only are int and bool
type Storable = Value
data Bindable = Const Value
| Variable Location
| Function Func
| Procedure Proce
deriving (Eq, Show)
data Denotable = Unbound | Bound Bindable
deriving (Eq, Show)
type Argument = Value
data Sval = Stored Storable | Undef | Unused
-- The actual storage in a Store
type DataStore = Location -> Sval
-- --bot--- --top--- --data---
data Store = Store (Location, Location, DataStore)
type Environ = Ident -> Denotable
-- ---------- Semantic Functions -------------- --
valuation :: Int -> Value
evaluate :: Expression -> Environ -> Store -> Value
elaborate :: Declaration -> Environ -> Store -> (Environ,Store)
execute :: Command -> Environ -> Store -> Store
-- the main goal is to define these semantic functions
-- I give some examples in my source code below.
my code is here: https://github.com/sanyuwen/IMP/blob/master/DSemImp.hs.
my test code is here: https://github.com/sanyuwen/IMP/blob/master/ImpTest.hs
when I use GHC to import DSemImp module, I encountered many errors.
DSemImp.hs:52:32: error:
Not in scope: type constructor or class ‘Identifier’
|
52 | data FormalParameter = Constfp Identifier | ^^^^^^^^^^
It said data FormalParameter = Constfp Identifier is not legal.
without this how can I define formal parameter ??
You didn't define Identifier. Though you defined Ident, is that what you meant?
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
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.