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
Related
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.
I'm very new to SML and I'm trying to add some items to a list
fun foo(inFile : string, outFile : string) = let
val file = TextIO.openIn inFile
val outStream = TextIO.openOut outFile
val contents = TextIO.inputAll file
val lines = String.tokens (fn c => c = #"\n") contents
val lines' = List.map splitFirstSpace lines
fun helper1(lis : string list) =
case lis of
[] => ( TextIO.closeIn file; TextIO.closeOut outStream)
| c::lis => ( TextIO.output(outStream, c);
helper1(lis))
fun helper(lis : (string * string) list, stack : string list) =
case lis of
[] => stack
| c::lis => ( act(#1 c, #2 c)::stack;
helper(lis, stack))
val x = helper(lines', [])
in
helper1(x)
end;
I'm getting a blank output file whenever I run the code and I'm having trouble figuring out why but I do know that the helper function is getting the proper values from the "act" function because I tested it by using print(action(...))
Thanks
The problem is with this part:
( act(#1 c, #2 c)::stack; helper(lis, stack) )
This is creating a new list and then immediately throwing it away before performing the recursive call. What you want to do instead is
helper(lis, act(#1 c, #2 c)::stack)
Additional hint: both your helper functions can be replaced by simple uses of List.app and List.foldl.
Edit: Further hint: In fact, you can write that as just
helper(lis, act(c)::stack)
because a function with "two arguments" is simply a function taking a pair.
(* function for union of two ordered sets*)
let rec search n list1 = match list1 with
[] -> false
| head :: tail when head = n -> true
| head :: tail when head != n -> search n tail
;;
(* function calls and output *)
Printf.printf("\nList = {");;
open Printf
let list1=[3;1;2;4];; (* Input first set here *)
let () = List.iter (printf " %d ") list1;;
printf("}");;
n=2;;
let u = search n list1;;
I am getting an error:
File "search.ml", line 15, characters 0-1:
Error: Unbound value n
Line 15 => "n=2;;"
Kindly inform whether it is a syntactic error or otherwise and possible remedy as well. Implementation is done on linux.
Expression n=2 compares n to 2, however n is not defined yet, so you get an error. You should use let n = 2 to bind values to names.
in OCaml to bound a value with a name one should use len name = value syntax
I just start working with standard ml and really have some trouble understanding the list in this language. So my question is how to shorten a list in ml ? For example, if I have a list [1,2,3,4,5,6], I want to shorten it to [1,2]. What I'm having so far is:
fun shorten(i, l) = let val newlen = i in newlen = length l//in correct
what I want is a function that will take i as a location that user want to shorten the list and l is the list. In this case, the input should look like shorten(2, [1,2,3,4,5,6] and the output should look like [1,2]
This function should do it:
fun shorten(_, nil) = nil
| shorten(0, _) = nil
| shorten(i, x::xs) = x::shorten(i - 1, xs)
As you noticed, this function doesn't throw any exceptions when i is larger than the length of the list. An approach that uses exceptions would be this:
exception IllegalArgument
fun shorten(_, nil) = nil
| shorten(0, _) = nil
| shorten(i, x::xs) =
if i > length(x::xs) then raise IllegalArgument
else x::shorten(i - 1, xs)
In SML you need to declare any exception type with exception before it is raised using raise. Otherwise, the exception type is not bound in the environment and the interpreter will complain about the symbol being unknown.
The SML Basis Library contains the function List.take to perform the required task as part of the List Structure.
- fun shorten ( toHowMany, myList ) = List.take ( myList, toHowMany ) ;
val shorten = fn : int * 'a list -> 'a list
- shorten ( 2, [1,2,3,4,5,6] ) ;
val it = [1,2] : int list
If the order of the arguments doesn't matter, then List.take can be used directly:
- List.take ( [1,2,3,4], 2 ) ;
val it = [1,2] : int list
What's the best way to insert an element in a list without returning a list? When I try to use the operator ::, it returns a list:
element :: lst
However, I would like the return value to be unit, similar to the way Hashtbl.add works.
What you want to do can't be done because lists are not changeable.
They are not changeable because this is "exactly not" how you do things in functional programming. You give the original list to a function and get a new list. If the list is good for something you keep working on it.
But there is hope: you could use a reference. Code from an interactive session:
# let mylist = ["one";"two";"tree"] ;;
val mylist : string list = ["one"; "two"; "tree"]
# mylist.[1];;
Error: This expression has type string list
but an expression was expected of type string
# mylist.(1);;
Error: This expression has type string list
but an expression was expected of type 'a array
# List.iter (function e -> print_endline e) mylist;;
one
two
tree
- : unit = ()
# let r = ref [];;
val r : '_a list ref = {contents = []}
# r := "zero" :: mylist;;
- : unit = ()
# List.iter (function e -> print_endline e) !r;;
zero
one
two
tree
- : unit = ()
# List.iter (function e -> print_endline e) ("minus" :: !r);;
minus
zero
one
two
tree
- : unit = ()
# List.iteri (fun cnt -> fun e -> Printf.printf "Element %d: %s" cnt e) !r;;
Element 0: zeroElement 1: oneElement 2: twoElement 3: tree- : unit = ()
#
Code walk:
define mylist
try to access one element in the list, not possible
another try to access one element, no go. You must be able to access it to store a new value
example of list iteration to print a list
create reference r of type '_a list ref
store string and mylist in r
iterate list in r for printing, to see if the data is there
iterate list with on the fly change of the list
finally give a (poor) example of List.iteri, in Caml syntax
I am so explicit because I was missing exactly these examples when trying to get aquainted with FP.
/Str.