Why am I getting these errors in my sml code? - sml

I'm creating an interpreter in Standard ML for Standard ML for an assignment but I can't seem to get past this problem.
I have this conditional in a function eval:
| eval (rho, SetExp (name, value)) =
(case rhoContains rho name of
true => rhoSet rho name value
| false => globalSet (name, value))
and these helper functions:
fun rhoSet [] key value = [(key, value)]
| rhoSet ((elt as (k, v)) :: tail) key value =
if key = k then (key, value) :: tail else elt :: rhoSet tail key value
fun rhoContains rho name =
case rhoGet rho name of SOME _ => true | NONE => false
fun globalSet key value =
let fun f [] = [(key, value)]
| f ((k,v)::tail) = if k = key then (k,value)::tail else (k,v)::f tail
in globals := f (!globals) end
Trying to run this gives me the following errors:
eval.sml:61: error: Clauses in case have different types.
Clause 1: true => rhoSet rho name value : bool -> (string * expression) list
Clause 2: false => globalSet (name, value) : bool -> int -> unit
Reason:
Can't unify (string * expression) list to int -> unit
(Incompatible types)
I'm not sure what's wrong at this point, and any help would be appreciated.

Related

This expression has type 'a list but an expression was expected of type 'b * 'c

I don't understand why I'm getting this error message, and I'd be glad to be enlightened about it
let write c v d =
let rec new_dict=function
| []->(k, v)
| (key,value)::q-> if key=k
then new_dict (q)
else (key,value)::new_dict (q)
in new_dict (d) ;;
Here i aimed to create a new dictionary in which the key 'c' would get a new value, or adding that key if it wasn't in the dictionary in the first place.
Sorry if my error is kind of obvious, I'm new to OcamL.
Thanks.
Let's consider new_dict only, with some formatting cleanup.
let rec new_dict =
function
| [] -> (k, v)
| (key, value)::q ->
if key = k then
new_dict q
else
(key, value) :: new_dict q
In the event the list is empty, it returns a tuple. Otherwise it returns a list. Note the :: list constructor.
Perhaps you meant:
let rec new_dict =
function
| [] -> [(k, v)]
| (key, value)::q ->
if key = k then
new_dict q
else
(key, value) :: new_dict q

How to return a SOME list instead of a normal list?

I am trying to implement a program that takes a string and a list and returns NONE if it doesn't find any match and the list without the element if it does.
fun all_except_option ("string",["he","she","string"]) = SOME["he","she"]
I have managed to make it working, but without the options type and i have no idea how to make it return SOME list instead a normal list.
fun all_except_option(str,lst)=
case lst of
[] => []
| x::lst' => if same_string(x,str) = false
then let fun append (word, list) = word::list
in append(x,[]) :: all_except_option(str,lst')
end
else all_except_option(str,lst')
Thank you. I managed to make it working, but i still don't understand the "else case" and how is my programm handling it. Here is the working code. I would be glad if you can explain me the "else case all_except_option(str,list') of".
fun all_except_option(str,list)=
case list of
[] => NONE
| x::list' => if same_string(x,str) then
SOME( list')
else case all_except_option(str,list') of
NONE=>NONE
| SOME list'=>SOME(x::list')
implement a program that takes a string and a list and returns NONE if it doesn't find any match and the list without the element if it does.
all_except_option ("string",["he","she","string"]) = SOME ["he","she"]
How is SOME [] different from NONE? As in, if this function returned just a list, it would be possible to say that removing occurrences of "string" results in no other strings: Either the list was empty already, or it contained only occurrences of "string". I am not sure why NONE vs. SOME [] is warranted in one case over the other.
So the better function is one that simply returns a plain list:
fun except (x, ys) = List.filter (fn y => x <> y)
When is it useful to return 'a option?
For example when the return type does not have a way to indicate no result already:
fun lookup k1 [] = NONE
| lookup k1 ((k2,v)::pairs) =
if k1 = k2
then SOME v
else lookup k1 pairs
This function returns 0 or 1 thing. But it's also a simple function because it never aggregates results over its recursion. Recursive functions become complicated when they return composite data types like 'a option when it needs to unpack the result of the recursion.
A good example is an eval function that sometimes fails:
datatype expr
= Add of expr * expr
| Sub of expr * expr
| Mul of expr * expr
| Div of expr * expr
| Int of int
fun eval (Int n) = SOME n
| eval (Add (e1, e2)) = evalHelper ( op+ ) (e1, e2)
| eval (Sub (e1, e2)) = evalHelper ( op- ) (e1, e2)
| eval (Mul (e1, e2)) = evalHelper ( op* ) (e1, e2)
| eval (Div (e1, e2)) =
case eval e1 of
NONE => NONE
| SOME x => case eval e2 of
NONE => NONE
| SOME 0 => NONE
| SOME y => SOME (x div y)
and evalHelper binop (e1, e2) =
case eval e1 of
NONE => NONE
| SOME x => case eval e2 of
NONE => NONE
| SOME y => SOME (binop (x, y))
Here the return type is int option, which means that you most often return an int, but if you ever divide by zero, that results in "no value", so rather than raise an exception, we return NONE, which necessitates us to return SOME n when there is a result, so that the type fits in both cases.
A quick demonstration:
- eval (Div (Int 5, Int 2));
> val it = SOME 2 : int option
- eval (Div (Int 5, Int 0));
> val it = NONE : int option
- eval (Div (Int 2, Sub (Int 3, Int 3)));
> val it = NONE : int option
- eval (Div (Int 0, Int 1));
> val it = SOME 0 : int option
Here SOME 0 actually means "the result is 0", which is not the same as "cannot divide by zero."

Finding a value in a function represented environment

When it came to finding a value in a bst env all I had to do was compare the value I was looking for with the root value at a node
type 'a tenv = (name * 'a) btree
exception NotFound of name
fun find compare name Leaf = raise NotFound name
| find compare name (Node (lt, (key, value), rt)) =
case compare(name, key) of
LESS => find compare name lt
| GREATER => find compare name rt
| EQUAL => value
But in a function represented env instead of a bst with nodes and leafs the find function is of type
name * 'a fenv -> 'a
and
type 'a fenv = name -> 'a
I get the general idea of the function but I'm confused as to how I would traverse the environment looking for the name. Bst has a node and a tree like structure. Can someone just give an explanation if possible?
EDITED IN
My working implementation is as such
exception NotFound of name
val Empty = fn name => raise NotFound name
fun Find(name, env) = env name
fun Bind(name, data, rho) = fn key => if key = name then data else rho
key
So an environment is now represented as a function that takes a name and either returns its value in the environment or raises an exception.
This function is going to be a composition of functions, and you "traverse" it by applying functions that represent older environments.
(This sounds more complicated than it is, but it can take a while to wrap your head around it.)
You can create the empty environment by writing a function that takes a name and raises an exception:
val empty = fn n => raise NotFound n
Finding things is much shorter than a tree lookup, since the environment already is that function:
fun find n env = env n
What remains is insertion:
fun insert (key, value) env = ... what?
It has to be a function that takes a name, since that's what an environment is
fun insert (key, value) env = fn n => ... what?
If n is the same as key, that function should return value:
fun insert (key, value) env = fn n => if n = key then value else ... what?
n might be found in the rest of the environment, so we apply that function in order to look for it there:
fun insert (key, value) env = fn n => if n = key then value else env n
And that's, as they say, it.
In a sense, the "traversal" code has moved from the lookup function to the insertion function.
Test:
- val env = insert ("hi", 23) empty;
val env = fn : string -> int
- find "hi" env;
val it = 23 : int
- find "hello" env;
uncaught exception NotFound
raised at: ...
- val env2 = insert ("hello", 999) env;
val env2 = fn : string -> int
- find "hello" env2;
val it = 999 : int
- find "hi" env2;
val it = 23 : int
As you can see, representing things as functions can be extremely compact.
In order to see what's happening, let's expand the first example:
val env = insert ("hi", 23) empty
Which is the same as (expanding the definition of insert):
val env = fn n => if n = "hi" then 23 else empty n
Successful lookup:
find "hi" env
is
env "hi"
which is
(fn n => if n = "hi" then 23 else empty n) "hi"
->
if "hi" = "hi" then 23 else empty n
->
23
Failure:
find "hello" env
->
(fn n => if n = "hi" then 23 else empty n) "hello"
->
if "hello" = "hi" then 23 else empty "hello"
->
empty "hello"
->
raise NotFound "hello"
Exception-handling example:
If you don't handle the exception, you will get an "uncaught exception" error, as in the example above.
You need to handle the exception in the code that uses find.
A trivial example:
fun contains n env = let val _ = find n env
in true
end
handle NotFound nm => false
- contains "hello" env;
val it = false : bool
- contains "hi" env;
val it = true : bool

right-hand-side of clause doesn't agree with function result type

Write a function remove_option, which takes a string and a string list. Return NONE if the string is not in the list, else return SOME xs where xs is identical to the argument list except the string is not in it. You may assume the string is in the list at most once. Use same_string, provided to you, to compare strings. Sample solution is around 8 lines.
The function type should be fn : string * string list -> string list option.Here is my code
fun same_string(s1 : string, s2 : string) =
s1 = s2
fun remove_option (str: string ,str_list : string list) =
case str_list of
[] => NONE
| x::xs => if same_string(x,str)
then SOME xs
else x :: remove_option( str,xs)
and the error report
hw2provided.sml:10.5-15.37 Error: right-hand-side of clause doesn't agree with f
unction result type [tycon mismatch]
expression: _ option
result type: string list
in declaration:
remove_option =
(fn (<pat> : string,<pat> : string list) =>
(case str_list
of <pat> => <exp>
| <pat> => <exp>))
uncaught exception Error
raised at: ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
../compiler/TopLevel/interact/evalloop.sml:44.55
../compiler/TopLevel/interact/evalloop.sml:292.17-292.20
So where is the bug ?
The problem is that you want to return a string list option but the line
else x :: remove_option( str,xs)
makes it seem that you want to return a string list
What you need to do with the return value of remove_option( str,xs) is
1) decide what to do if it is NONE
2) extract the string list strings (or whatever you want to call it) if it is of the form SOME strings, tack x onto the front of the list, and repackage it with SOME before returning it.
You seem comfortable with the use of case, so you could use it here.
Since John showed where the bug is, here are some extra comments:
Since the function same_string is not injected, it is superfluous. You might as well use =.
Recursive functions that return 'a option are kind of tricky, since you need to unpack the result:
fun remove_option (s1, []) = NONE
| remove_option (s1, s2::ss) =
if s1 = s2
then SOME ss
else case remove_option (s1, ss) of
NONE => NONE
| SOME ss' => SOME (s2::ss')
Generally, when you see the pattern
case x_opt of
NONE => NONE
| SOME x => SOME (f x))
this can be refactored into using e.g. Option.map : ('a -> 'b) -> 'a option -> 'b option:
Option.map f x_opt
In this case,
fun curry f x y = f (x, y)
fun remove_option (s1, []) = NONE
| remove_option (s1, s2::ss) =
if s1 = s2
then SOME ss
else Option.map (curry op:: s2) (remove_option (s1, ss))
where curry op:: s2, the function that puts s2 in front of a list.

Haskell Beginner without a Clue

It took me a while to even work out what this question was looking for. I have to return only those propositions that give an overall evaluation of True. Our example is And p (Or q (Not q)) and I know that p has to be True and q can be either True or False. To achieve our goal we have been given a few functions to start with.
type Variable = String
type Valuation = [(Variable, Bool)]
data Prop = Falsum -- a contradiction, or
| Var Variable -- a variable, or
| Not Prop -- a negation of a formula, or
| Or Prop Prop -- a disjunction of two formulae, or
| And Prop Prop -- a conjunction of two formulae, or
| Imp Prop Prop -- a conditional of two formulae.
deriving (Eq, Show)
example = And p (Or q (Not q))
vars :: Prop -> [Variable]
vars = nub . vars'
where
vars' Falsum = []
vars' (Var v) = [v]
vars' (Not f) = vars' f
vars' (Or f g) = vars' f ++ vars' g
vars' (And f g) = vars' f ++ vars' g
vars' (Imp f g) = vars' f ++ vars' g
eval :: Valuation -> Prop -> Bool
eval val Falsum = False
eval val (Var v) = case (lookup v val) of
Nothing -> error ("Unbound variable: " ++ v)
Just t -> t
eval val (Not f) = not (eval val f)
eval val (Or f g) = (eval val f) || (eval val g)
eval val (And f g) = (eval val f) && (eval val g)
eval val (Imp f g) = eval val (Or (Not f) g)
valuations :: [Variable] -> [Valuation]
valuations [] = [[]]
valuations (v:vs) = map ((v,True):) ds ++ map ((v,False):) ds
where ds = valuations vs
I now have to write a models function and I worked out that the typeline has to be
models :: Prop -> [Valuations]
as my example must return the list of Valuations that are evaluate to True which is:
models example == [[("p",True)("q",True)],[("p",True)("q",False)]]
I know that vars returns the list of variables without duplicates, in this case ["p","q"], and that passing the result from vars into valuations produces the list of all possible outcomes of applying True and False to both "p" and "q". So far I can only get the first output of this list to evaluate using the evals function. Here's my code:
models :: Prop -> Bool
models form = eval v form where (v:vs) = valuations (vars form)
I have tried to change the code to evaluate the rest of vs but I keep getting an error message:
Couldn't match expected type '[Bool]' with actual type 'Bool'
Here's my altered code:
models :: Prop -> [Bool]
models form = eval v form : eval vs form where (v:vs) = valuations (vars form)
Ideally I believe I would want to discard the eval results rather than keep them in a list and only return those valuations which evaluate to True. I'm just stuck on how to recursively evaluate the rest of vs.
I believe once I can evaluate all elements in my list using the evals function then I can just add the ones that evaluate to True using some form of equality assignment, such as:
where finalList == True =
Alas, that doesn't even look close to being correct.
Any help with my logic would be helpful. Oh and an explanation as to how I can recursive evaluate the rest of the list would be appreciated.
I'm going to assume you want models :: Prop -> [Valuation] like you started to write. Models will return every Valuation that satisfies the proposition. Starting with something close to what you had
models form = valuations (vars form)
gets us halfway there; it has the correct type, Prop -> [Valuation]. This just lists every Valuation for the variables in form. What we'd like is to have only those results which satisfy the proposition. These can be determined by your eval function.
models :: Prop -> [Valuation]
models form = filter satisfies (valuations (vars form))
where satisfies val = eval val form
To run this, we need to fix your example so it compiles, and maybe add a couple examples of my own:
example = And (Var "p") (Or (Var "q") (Not (Var "q")))
main = do
print $ models Falsum
print $ models example
print $ models $ And (Var "p") (Not (Var "p"))
print $ models $ Or (Var "p") (Not (Var "p"))
This outputs
[]
[[("p",True),("q",True)],[("p",True),("q",False)]]
[]
[[("p",True)],[("p",False)]]
Now, we might also want a function that checks to see if there exists any Valuation that satisfies the proposition. This would take a proposition and return a boolean.
satisfiable :: Prop -> Bool
We can easily write this in terms of models
satisfiable :: Prop -> Bool
satisfiable = not . null . models
For the same four examples
main = do
print $ satisfiable Falsum
print $ satisfiable example
print $ satisfiable $ And (Var "p") (Not (Var "p"))
print $ satisfiable $ Or (Var "p") (Not (Var "p"))
This outputs
False
True
False
True