How to add function and procedure abstractions denotational semantics using haskell? [closed] - haskell

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?

Related

Writing an interpreter for an imperative language in Haskell

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.

How to check for the argument of a function and pass it on?

I'm trying to code a function that takes one of my own commands and its argument if it has got one and passes on the argument only. Of course "int" is not in scope, but if I try to pass it on with x (like "f (x int)") I get a parse error. I'm new to Haskell and grateful for any advice.
data Command = PushC Int | Pop | Push Int
f :: Command -> Int
f x | x == PushC int = int
| x == Pop = 1
| x == Push int = int
| otherwise = -1
I just want to check for any Integer as argument of the command and have it as output. If the command doesen't have an argument output 1.
You really should use pattern matching [Haskell-wiki] here:
f :: Command -> Int
f (PushC n) = n
f (Push n) = n
f Pop = 1
Pattern matching is more effective than using (==) :: Eq a => a -> a -> Bool, first of all, not all types are an instance of Eq, and furthermore you can not match parameters of the data constructor with Eq. You can thus not match some_val == PushC num, and hope that Haskell assigns a value to num, like Prolog does.
Usually (==) and (/=) are only used to check if two values are equal, not to discriminate between the possible data constructors and parameters of a type.
You could use a wild card (_) as last clause here, but it is probably better not to do that: if you later add an extra Command data constructor, the compiler can warn you that not all patterns are covered, and thus you can provide the correct expression. If on the other hand, you use a wildcard, then that clause will automatically be matched with that data constructor, and this might not be the intended effect.

Executing Parsed function calls in Haskell

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 = ?

Type casting when working with nested data structures

I have the following data structures defined:
data Operator = Plus | Times | Minus deriving (Eq,Show)
data Variable = A | B | C deriving (Eq,Show)
newtype Const = D Numeral deriving (Eq,Show)
data CVO = Const | Variable | Operator deriving (Eq,Show)
type Expr = [CVO]
I have defined the following function:
eval2 :: Expr -> Integer
eval2 x = helper x
I would like to check if an element of the CVO list (Expr) is either an instance of Const, Variable or Operator (this works) and I would like to implement varying code for the specific type of the instance (e.g. Plus, Times, Minus for Operator).
helper :: Expr -> Integer
helper [] = 2
helper (x:xs)
| x == Operator && x == Plus = 1
I cannot compare x to Plus, because it expects x to be of type CVO.
Couldn't match expected type ‘CVO’ with actual type ‘Operator’
Is it somehow possible to cast x to be an instance of Operator in order to do the comparison?
A value can't have two different types at the same time. If x is a CVO you can't use == to compare it to Plus which is an Operator.
At the moment the type CVO consists of three constant values called Const, Variable and Operator. I'm guessing you actually wanted it to contain values of the type Const, Variable or Operator. You do that by declaring arguments to the constructors.
data CVO = Const Const -- a constructor whose name is Const and contains a value of type Const
| Var Variable -- a constructor named Var containing a Variable
| Op Operator -- a constructor named Op containing an Operator
A given value of type CVO must have been built from one of those three constructors, containing a value of the correct type. You can test which constructor was used to create the CVO, and simultaneously unpack the value, using pattern matching. Something like this:
helper :: Expr -> Integer
helper [] = 0
helper (Op o:xs) -- because we matched Op, we know o :: Operator
| o == Plus = 1
| otherwise = 2
helper _ = 3

Interpreter of a small imperative language

Hi I'm writing an interpreter of C-like, statically typed language in Haskell. I want to perform typechecking before an execution of code, but I have some problems with it. First of all, below there are some type definitions from my abstract syntax:
newtype Ident = Ident String deriving (Eq,Ord,Show)
data Exp = {-- some other value constructors --} | EFuncWithParams Ident [Exp]
data Type = TInt | TDouble | {-- some other value constructors --} | TFunction [Exp]
type TCM a = ErrorT String (Reader Env) a
TCM is for reporting errors and passing the enviroment, eg:
typeof (EVar v) = do
env <- ask
case M.lookup v env of
Nothing -> throwError $ "undefined variable" ++ v ++ "\n"
Just t - > return t
Now I want to check type of expressions so I have following function that performs checks:
typeof Exp :: Exp -> TCM Type
It is defined for all cases but one:
typeof (EFuncWithParams f l)
I'm stuck here. What I think I should do is to check the type of f (I mean first of all check if it really IS a function) and see whether types of arguments that are recorded in definition of f match types of arguments that are actually passed. Unfortunately I'm a haskell newbie and have no idea on how to express it the right way. Any suggestions will be highly appreciated :)
EDIT:
OK, It may not be implied by what I wrote here previously but EFuncWithParams Ident [Exp] is a function call actually (Yes, I know it is somewhat misleading) and I want to be able to call a function like f(2 + 3, a, b[0]) and this is why I used TFunction [Exp]. Function declaration and definition is a statement and is defined:
data Function_def =
Func Type_specifier Declarator Compound_stm
deriving (Eq,Ord,Show)
where Declarator is:
data Declarator = FuncDec Ident Parameter_declarations
Parameter declarations is a list of Type_specifiers and Idents
What I think I should do is to save function type in a map while checking its declaration, and then fetch it here. I mean I also have:
typeof_stm :: Stm -> TCM Type -- Function_def is a statement
The problem is that I have a separate function for type-checking statements and I am in doubt whether the map that is used by one function (eg. typeof_stm) is passed automatically to another one (eg. typeof). I see no way of this to happen but maybe I'm wrong.
I think your function type is wrong. You have it as TFunction [Exp], it should be TFunction [Type] Type (a list of argument types and a return type).
Typechecking code for a function call would look something like
case ... of ...
EFuncWithParams ident args -> do
t <- typeof (EVar ident)
ts <- mapM typeof args
case t of
TFunction ps r -> if ts == ps
then return r
else throwError $ "parameter types do not match"
_ -> throwError $ "called id " ++ ident ++ " which is not a function"
This pseudo-code probably goes in and out of the monad improperly, please bear with me, I don't have all of your code so I cannot really typecheck what I have done. But the overall scheme is like this. You probably will want to give more detailed error report if parameter types do not match (which ones don't match, or perhaps there's a wrong number of parameters).
I'm not practical with Haskell, I just did it in OCaml and in C++ but what you are going to do is to call the type checker function recursively on each parameter and check if they do correspond.
What I mean is that you'll have to type check something that is like
FunCall ident, exp list
Now you'll have in the environment an entry for the function with the types of parameters associated so what you need to ensure in order is that:
function named ident does exist in the environment
the number of parameters is equal to the definition (this can be done implicitly by the param checking function, see below)
for every parameter you call typeof (exp1) and you check that the returned TCM Type is the same of the corresponding parameter
This is how it should work. In OCaml (which is somewhat similar to Haskell) I would do something like:
match exp with
| FunCall ident, (param list) ->
(* get fundecl from ident *)
(* call check_params list_of_parameters, list_of_type_of_parameters *)
(* if check params return true then type check value of the function is the return value *)
let check_params list decl_list =
match list, decl_list with
| [], [] -> true
| p :: rp, d :: rd -> typeof(p) = d && check_params rp rd
| _ -> false
EFuncWithParams Ident [Exp]
It is typical for languages like yours to require a type annotation on the input, and possibly also a type annotation on the output. So if you add this info to that constructor
EFuncWithparams { inType, outType :: Type
, funcInput :: Ident
, funcBody :: [Expr] }
Now to typecheck it, you simply:
Add the binding of funcInput to inType to your type environment
Ascertain the type of funcBody with the new type environment
Make sure it matches with outType.
You should also check function applications to make sure that the input matches the function's inType, and that the results are used correctly according to its outType.

Resources