Im having trouble understanding this implementation of lists in Standard ML. Here is how it is defined:
An append list is a (simple) implementation of the list abstract data type that makes construction cheap (O(1)), but makes destruction expensive (O(n)). The 'a alistNN and 'a alist types are defined as follows:
datatype 'a alistNN = Sing of 'a | Append of 'a alistNN * 'a alistNN
datatype 'a alist = Nil | NonNil of 'a alistNN
The 'a alistNN type represents the “non-nil” append lists, while the 'a alist type represents arbitrary (nil or
non-nil) append lists.
Im confused on how I would work with these lists/make these lists. For example I have to write a function that is defined as:
'a alist -> 'a alist -> 'a alist that appends to append lists.
Any help will be appreciated in understanding this list definition.
This data structure represents a list with a tree, where each internal node represents concatenation of its children, and each leaf is an element. For example, here's two possible representations for the list [1,2,3,4]:
val L1 = Append (Append (Sing 1, Sing 2), Append (Sing 3, Sing 4))
*
/ \
* *
/ \ / \
1 2 3 4
val L2 = Append (Append (Sing 1, Append (Sing 2, Sing 3)), Sing 4)
*
/ \
* 4
/ \
1 *
/ \
2 3
Appending these data structures is extremely easy; you just link them together with a new Append node. We could append the two examples above:
Append (L1, L2)
*
/ \
/ \
* *
/ \ / \
* * * 4
/ \ / \ / \
1 2 3 4 1 *
/ \
2 3
Obviously you'll also have to wrap these in NonNil as appropriate, but I'll leave that to you.
With normal lists,
datatype 'a normal_list = Nil | Cons of 'a * 'a normal_list
your Cons operator to prepend a single element is O(1), but to append two lists is O(n):
fun append (Nil, ys) = ys
| append (xs, Nil) = xs
| append (Cons (x, xs), ys) = Cons (x, append (xs, ys))
With these append lists,
datatype 'a alistNN = Sing of 'a | Append of 'a alistNN * 'a alistNN
datatype 'a alist = Nil | NonNil of 'a alistNN
your Append operator is now the O(1), but cons becomes the more difficult O(n) because, as you say, it requires destroying the list to rebuild it, since the head of the data structure is no longer the first element, but rather the point at which the list was most recently appended.
Im confused on how I would work with these lists/make these lists. For example I have to write a function that is defined as:
'a alist -> 'a alist -> 'a alist
that appends to append lists.
(Edit: Clarified this section.) You already have a constructor Append : 'a alistNN * 'a alistNN -> 'a alistNN that does just that. To make one that instead works for 'a alist, you have to pattern match against the different cases of 'a alist; only when both lists are NonNil can you use Append (since an empty list is not expressible as an 'a alistNN. The cases where either operand is Nil can be handled separately;
fun append Nil ys = ys
| append xs Nil = xs
| append (NonNil xs) (NonNil ys) = NonNil (Append (xs, ys))
One thing that becomes more difficult is if you want to prepend a single element in front of an 'a alist, i.e. a function with the signature 'a * 'a alist -> 'a alist:
fun cons (x, Nil) = NonNil (...)
| cons (x, NonNil (Sing y)) = NonNil (...)
| cons (x, NonNil (Append (ys, zs))) = NonNil (...)
In every case x is prepended. There are three cases when it comes to the list to which you're prepending x: Either the list is empty, the list is non-empty and contains a single element, or the list is non-empty and contains the Append of two other lists. In every case, the result is something NonNil, since prepending an x to a list will never give Nil.
The first two cases should be straight forward. The third case you have to think about where to put x in terms of the sub-lists ys and zs.
Like this you can build all the auxiliary functions found by typing open List; in a REPL. Even hd and tl are not completely trivial because they're bent on finding the split between the first element and the rest of the list. A useful function for testing purposes would be toList with the signature 'a alist -> 'a list. A funny one to make for these append lists is rev. :-)
Since you're probably not going to make foldl:
fun foldl f e Nil = e
| foldl f e (NonNil (Sing x)) = f (x, e)
| foldl f e (NonNil (Append (xs, ys))) =
foldl f (foldl f e (NonNil xs)) (NonNil ys)
For amusement, you could implement hd using foldl and throwing an exception:
fun hd xs =
let exception FoundIt of 'a
in foldl (fn (x, _) => raise FoundIt x) (fn _ => raise Empty) xs ()
handle FoundIt x => x
end
Here's a slightly related StackOverflow post: Standard ML functor examples
Related
So far, I've made a function which matches all elements of one list with only the first element of another list, but I need it to match all elements of list 1 with all elements of list 2.
My code so far looks like this:
let prototype (lst1: 'a list) (lst2: 'b list) =
List.map (fun i -> [i,lst2.Head]) lst1 |> List.concat
So you figured out how to pair all elements of lst1 with a single thing. Great!
Now look: inside the map's parameter, you have the exact same problem - pair every element of lst2 with i. So you can just solve it the exact same way:
let prototype (lst1: 'a list) (lst2: 'b list) =
List.map (fun i -> List.map (fun j -> [i, j]) lst2 |> List.concat) lst1 |> List.concat
But this is a bit ugly of course. There are a few minor modifications you can make to make it prettier.
First, note that List.map >> List.concat is equivalent to List.collect:
let prototype (lst1: 'a list) (lst2: 'b list) =
List.collect (fun i -> List.collect (fun j -> [i, j]) lst2) lst1
But of course a much better option is to use list comprehensions:
let prototype (lst1: 'a list) (lst2: 'b list) =
[ for i in lst1 do
for j in lst2 ->
i, j
]
Here is an example
Examples:
- unnest;
val it = fn : 'a NestedList -> 'a list
(* [1,2,3] *)
- unnest(List [(Atom 1), (Atom 2), (Atom 3)]);
val it = [1,2,3] : int list
I was give
datatype 'a NestedList =
Nil
| Atom of 'a
| List of 'a NestedList list;
What I have so far
fun unnest(Nil) = []
| unnest(Atom(x)) = [x]
| unnest(List(x::xs)) = unnest(x);
which only gives the head part of the list and I do not know how to get to the rest of list.
I understand there is a way using concat and map and fn but is there without using library function?
Applying unnest to a NestedList value is meant to yield a plain old list. So we know the type of this function must be:
'a NestedList -> 'a list
When we apply unnest to a List, we need to recursively apply it to each element in that contained list.
There are two issues with your function.
It doesn't account for an empty list in the pattern-matching.
It only acts on the first item in a non-empty list.
If we map unnest to each element in that contained list, we'll get a list of lists. This isn't what we ultimately want, but we can work with it.
fun unnest(Nil) = []
| unnest(Atom(x)) = [x]
| unnest(List(lst)) = map unnest lst
The above won't compile because the final case yields an 'a list list. How can we turn a list of lists into just a list?
We can concatenate two lists with the # operator, and that means we can fold this over the lists to get a flattened list.
fun unnest(Nil) = []
| unnest(Atom(x)) = [x]
| unnest(List(lst)) = foldl op# [] (map unnest lst)
Evaluating unnest(List [(Atom 1), (Atom 2), (Atom 3)]) now gets us [3, 2, 1]. This is reversed because of the order in which foldl sends arguments to op#. If we write an anonymous function we can correct this.
fun unnest(Nil) = []
| unnest(Atom(x)) = [x]
| unnest(List(lst)) = foldl (fn (x, i) => i # x) [] (map unnest lst)
I have a function in OCaml which should merge two lists:
let rec merge (list1, list2) =
match (list1, list2) with
([], []) -> merge (List.tl list1, List.tl list2) :: List.hd list1 :: List.hd list2
|(_, []) -> merge (List.tl list1, list2) :: List.hd list1
|([], _) -> merge (list1, List.tl list2) :: List.hd list2;;
but for some reason the compiler doesn't let this code through exitting with:
Error: This expression has type 'a list
but an expression was expected of type 'a
The type variable 'a occurs inside 'a list
How can I specify that these are lists of 'a I'm trying pass, not 'a?
First of all, this function won't work. If the two lists are empty you merge the tail and concatenate the head of each of them but...well...they are empty...
Anyway, your problem is that you're using the :: operator (concatenation) whose type is 'a -> 'a list -> 'a list so the left member should be an element and the right one a list, here the left one is the list and the right one the element so it can not work.
About your question, since the type is inferred, you can't tell the compiler that you're right and he's wrong, in this case the error was truly explicit :
List.tl l (* 'a list *) :: List.hd l (* 'a *)
will always return an error because you have an infinite type (since :: is of type 'a -> 'a list -> 'a list, I let you try to determine a finite type 'a that could match with your concatenation)
So, I guess what you want to do is something like this :
let rec merge (list1, list2) =
match list1, list2 with
| [], _ -> list2;;
| hd :: tl, _ -> hd :: merge tl list2
I am trying to make a list of pairs in ocaml, but the problem is when the lists' length are different i don't hot to make pairs (a,b) when one of the elements doesn't exist.
Most likely you'll have to create a type to encapsulate the situations of the differing length,
type ('a,'b) combined = Both of 'a * 'b | Left of 'a | Right of 'b
let rec zipwith xs ys = match xs,ys with
| x::xs,y::ys -> Both (x,y) :: (zipwith xs ys)
| x::xs, [] -> Left x :: (zipwith xs ys)
| [], y::ys -> Right y :: (zipwith xs ys)
| [], [] -> []
# zipwith [1;2;3] [1;2];;
- : (int, int) combined list = [Both (1, 1); Both (2, 2); Left 3]
You'll have to make optimizations regarding tail-calls for this to work on long lists, but this is a start of how to approach the problem.
I would appreciate if someone could guide me here, I really want to understand what I did wrong and why?
This is my code:
fun get_longest xs = foldl((fn (x ,y ) => if String.size x >= String.size y then x
else y),[],xs)
My function should take a list of strings and return the longest string; if the list is empty, just return [].
But I'm getting this error:
Error: operator and operand don't agree [tycon mismatch]
operator domain: 'Z * 'Y -> 'Y
operand: (string * string -> string) * int * 'X
in expression:
foldl ((fn (<pat>,<pat>) => if <exp> then <exp> else <exp>),0,xs)
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:296.17-296.20
Take a look at the signature of foldl:
val foldl : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
You can see that your function should have the form
fun get_longest xs = foldl foo acc xs
where foo is the function applies on an element and an accumulator and acc is the initial accumulator.
Hints:
Since get_longest returns a string, the accumulator should have type string. Your job is to find out a suitable string to fill in. Note that the value [] you want here doesn't make sense.
xs is a string list, your foo function should have type string * string -> string. Now you have to replace foo by an appropriate anonymous function.
foldl is a curried functions, it's type is ('a * 'b -> 'b) -> 'b -> 'a list -> 'b. Therefore it should be called as foldl f s xs. You're calling it as foldl (f, s, xs). That's wrong because it calls foldl with a tuple as its argument and foldl does not expect a tuple. If it did, its type would be ('a * 'b -> 'b) * 'b * 'a list -> 'b.