My custom datatype is defined as follows: datatype 'a mylist = NIL | CONS of 'a * 'a mylist;
Been trying for hours but can't figure out how to reverse such a list.
My code that doesn't work:
fun reverse NIL = NIL
| reverse (CONS(head,tail)) = reverse tail # [head];
Here is the function call:
reverse (CONS(4,CONS(3,CONS(2,NIL))));
Use of the append operator will increase the time complexity of this solution. I would instead use a helper function in order to perform a tail-recursive call whereby the list is reversed in a stack-like manner.
e.g.
fun reverse xs =
let
fun revhelp NIL ys = ys
| revhelp (CONS(x,xs)) ys = revhelp xs (CONS(x,ys))
in
revhelp xs NIL
end;
You can't use the builtin append (#) and lists ([head]) with your own list type.
You need CONS (head, NIL) instead of [head], and you need to write your own
append: 'a mylist -> 'a mylist -> 'a mylist
or
append: ('a mylist * 'a mylist) -> 'a mylist
Implementing append left as an exercise.
Related
The motivating problem is: Code a lazy list whose elements are all possible combinations of 0 and 1 i.e. [0], [1], [0;0], [0;1], etc..
Working in OCaml, I've written auxiliary functions for generating the list of permutations of length n+1 given n and for converting a list into a lazy list. The problem comes from the final function in the below block of code:
type 'a seq =
| Nil
| Cons of 'a * (unit -> 'a seq)
let rec adder = function
| [] -> []
| [[]] -> [[0];[1]]
| xs::ys -> (0::xs)::(1::xs)::(adder ys)
let rec listtoseq = function
| [] -> Nil
| xs::ys -> Cons(xs, fun () -> listtoseq ys)
let rec appendq xq yq =
match xq with
| Nil -> yq
| Cons (x, xf) -> Cons (x, fun() -> appendq (xf ()) yq)
let genlist xs = appendq (listtoseq xs) (genlist (adder xs))
Calling genlist [[0];[1]] results in a stack overflow. The issue seems to be that since genlist is an infinite loop I want to delay evaluation, yet evaluation is needed for appendq to work.
If this were a problem where one element is added to the lazy list at a time I could solve it, but I think the difficulty is that each set of length n permutations must be added at a time, and thus I don't know any other solution besides using an append function.
One way to look at your problem is that appendq isn't lazy enough. You can make things work if you define a function appendqf with this type:
'a seq -> (unit -> 'a seq) -> 'a seq
In other words, the second parameter isn't a sequence. It's a function that returns a sequence.
(Note that this type, unit -> 'a seq, is what actually appears inside a Cons.)
I tried this and it works for me.
As the title suggests, I want to write a function that takes in an 'a list and an expression that evaluates to either true or false when elements of the list are passed into it. The function should return an 'a list of all the elements that don't satisfy the predicate given. The type should be
'a list -> ('a -> bool) -> 'a list
when it is working properly.
This is what I have so far,
let rec filter (x: 'a list) pred =
if x = [] then [] else
if x -> pred = true then remove_if (x.tl) pred else
x :: xs remove_if (x.tl) pred ;;
I tried some other ways of writing it but in my closest attempt the type ended up evaluating improperly.
Here's something to get you started..
let rec filter f lst =
match lst with
| [] -> []
| hd::tl ->
if (f hd)
(*The rest of the function goes here*)
In OCaml, a typical fold function looks like this:
let rec fold (combine: 'a -> 'b -> 'b) (base: 'b) (l: 'a list) : 'b =
begin match l with
| [] -> base
| x :: xs -> combine x (fold combine base xs)
end
For those familiar with OCaml (unlike me), it should be pretty straightforward what it's doing.
I'm writing a function that returns true when all items in the list satisfy the condition: if condition x is true for all x in some list l. However I'm implementing the function using a fold function and I'm stuck. Specifically I don't know what the list should return. I know that ideally the condition should be applied to every item in the list but I have no idea how the syntax should look. x && acc works but it fails a very simply test (shown below)
let test () : bool =
not (for_all (fun x -> x > 0) [1; 2; -5; -33; 2])
;; run_test "for_all: multiple elements; returns false" test
Here is my preliminary attempt. Any help is appreciated:
let for_all (pred: 'a -> bool) (l: 'a list) : bool =
fold (fun(x:'a)(acc: bool)-> _?_&&_?_ )false l
let rec fold (combine: 'a -> 'b -> 'b) (base: 'b) (l: 'a list) : 'b =
match l with
| [] -> base
| x::xs -> combine x (fold combine base xs)
let for_all (pred: 'a -> bool) (lst: 'a list) =
let combine x accum =
(pred x) && accum
in
fold combine true lst
Your combine function should not do x && base because elements of the list are not usually bool. You want your predicate function first evaluate the element to bool, then you "and" it with the accumulator.
There is no need for begin and end in fold. You can just pattern match with match <identifier> with.
There are two widespread types of fold: fold_left and fold_right. You're are using fold_right, which, basically, goes through the whole list and begins "combining" from the end of the list to the front. This is not tail-recursive.
fold_left, on the other hand goes from the front of the list and combines every element with the accumulator right away. This does not "eat up" your stack by a number of recursive function calls.
Functors in Standard ML are related to the module system and can generate structures based on other structures. An example of a functor generating list combinators for various types of lists is given below, but this example has a problem:
The various types of lists all have advantages -- for example, lazy lists can be infinitely long, and concantenation lists have a O(1) concat operator. But when all of these list types conform to the same signature, the functor can only use their general properties.
My question is therefore: What is a good example of when functors are useful and the various generated structures don't lose their special abilities?
signature MYLIST =
sig
type 'a t
val null : 'a t -> bool
val empty : 'a t
val cons : 'a * 'a t -> 'a t
val hd : 'a t -> 'a
val tl : 'a t -> 'a t
end
structure RegularList : MYLIST =
struct
type 'a t = 'a list
val null = List.null
val empty = []
val cons = op::
val hd = List.hd
val tl = List.tl
end
structure LazyList : MYLIST =
struct
datatype 'a t = Nil | Cons of 'a * (unit -> 'a t)
val empty = Nil
fun null Nil = true
| null _ = false
fun cons (x, xs) = Cons (x, fn () => xs)
fun hd Nil = raise Empty
| hd (Cons (x, _)) = x
fun tl Nil = raise Empty
| tl (Cons (_, f)) = f ()
end
structure ConcatList : MYLIST =
struct
datatype 'a t = Nil | Singleton of 'a | Concat of 'a t * 'a t
val empty = Nil
fun null Nil = true
| null (Singleton _) = false
| null (Concat (xs, ys)) = null xs andalso null ys
fun cons (x, xs) = Concat (Singleton x, xs)
fun hd Nil = raise Empty
| hd (Singleton x) = x
| hd (Concat (xs, ys)) = hd xs
fun tl Nil = raise Empty
| tl (Singleton x) = Nil
| tl (Concat (xs, ys)) = (* exercise *)
end
signature MYLISTCOMB =
sig
type 'a t
val length : 'a liste -> int
val map : ('a -> 'b) -> 'a liste -> 'b liste
val foldl : ('a * 'b -> 'b) -> 'b -> 'a liste -> 'b
val append : 'a liste * 'a liste -> 'a liste
val concat : 'a liste liste -> 'a liste
val sort : ('a * 'a -> order) -> 'a t -> 'a t
end
functor ListComb (X : MYLIST) : MYLISTCOMB =
struct
type 'a t = 'a X.t
open X
fun length xs =
if null xs then 0
else 1 + length (tl xs)
fun map f xs =
if null xs then empty
else cons(f (hd xs), map f (tl xs))
fun foldl f e xs =
if null xs then e
else foldl f (f (hd xs, e)) (tl xs)
fun append (xs, ys) =
if null xs then ys
else cons (hd xs, append (tl xs, ys))
fun concat xs =
if null xs then empty
else append (hd xs, concat (tl xs))
fun sort cmp xs = (* exercise *)
end
structure RegularListComb = ListComb (RegularList)
structure LazyListComb = ListComb (LazyList)
structure ConcatListComb = ListComb (ConcatList)
Not sure I fully understand your question. Obviously, functors are useful for defining modular abstractions that (1) are polymorphic, (2) require a whole set of operations over their type parameters, and (3) provide types as part of their result (in particular, abstract types), and (4) provide an entire set of operations.
Note that your example doesn't make use of (3), which probably is the most interesting aspect of functors. Imagine, for example, implementing an abstract matrix type that you want to parameterise over the vector type it is based on.
One specific characteristic of ML functors -- as well as of core-language polymorphic functions -- is that they are parametric. Parametricity is a semantic property saying that evaluation (of polymorphic code) is oblivious to the concrete type(s) it is instantiated with. That is an important property, as it implies all kinds of semantic goodness. In particular, it provides very strong abstraction and reasoning principles (see e.g. Wadler's "Theorem's for free!", or the brief explanation I gave in reply to another question). It also is the basis for type-erasing compilation (i.e., no types are needed at runtime).
Parametricity implies that a single functor cannot have different implementations for different types -- which seems to be what you are asking about. But of course, you are free to write multiple functors that make different semantic/complexity assumptions about their parameters.
Hope that kind of answers your question.
Here is a number of useful examples of SML functors. They are made on the following premise: If you can do one set of things, this enables you to do another set of things.
A functor for sets: If you can compare elements, you can create sets using balanced data structures (e.g. binary search trees or other kinds of trees).
signature SET =
sig
type elem
type set
val empty : set
val singleton : elem -> set
val union : set -> set -> set
val intersect : set -> set -> set
end
signature ORD =
sig
type t
val compare : t * t -> order
end
functor BalancedSetFunctor(structure Cmp : ORD) :> SET =
struct
type elem = Cmp.t
type set = ...
val empty = ...
fun singleton x = ...
fun union s1 s2 = ...
fun intersect s1 s2 = ...
end
A functor for iteration: For any kind of collection of things (e.g. lists), if you can iterate them, you can automatically fold them. You can also create different structures for different ways to fold across the same datatype (e.g. pre-order, in-order and post-order traversal of trees).
signature ITERABLE =
sig
type elem
type collection
val next : collection -> (elem * collection) option
end
signature FOLD =
sig
type elem
type collection
val fold : (elem * 'b -> 'b) -> 'b -> collection -> 'b
end
functor FoldFunctor(Iter : ITERABLE) :> FOLD =
struct
type elem = Iter.elem
type collection = Iter.collection
fun fold f e xs =
case Iter.next xs of
NONE => e
| SOME (x, xs') => fold f (f (x, e)) xs'
end
Functors are "lifters" - they lift (this verb is standard FP terminology): for a given set of types and values, they let you create a new set of types and values on top of them.
All the modules conforming to the required module interface can "benefit" from the functor, but they don't lose their special abilities, if by abilities you mean the implementation specific advantages.
Your very example, for instance, works well to demonstrate my point: concatenation lists have a very fast concat operator, as you wrote, and when lifted with the functor, this 'ability' doesn't vanish. It's still there and perhaps even used by the functor code. So in this example the functor code actually benefit from the list implementation, without knowing it. That's a very powerful concept.
On the other hand, since modules have to fit an interface when lifted by a functor, the superfluous values and types are lost in the process, which can be annoying. Still, depending on the ML dialect, this restriction might be somewhat relaxed.
I was trying to make a tail-recursive version of this very simple SML function:
fun suffixes [] = [[]]
| suffixes (x::xs) = (x::xs) :: suffixes xs;
During the course of this, I was using type annotations on the paramaters. The following code shows this, and causes a type error (given below), whereas if I simply remove the type annotations, SML accepts it with no problem, giving the whole function the same signature as the simpler function above.
fun suffixes_tail xs =
let
fun suffixes_helper [] acc = []::acc
| suffixes_helper (x::xs:'a list) (acc:'b list) =
suffixes_helper xs ((x::xs)::acc)
in
suffixes_helper xs []
end;
Error:
$ sml typeerror.sml
Standard ML of New Jersey v110.71 [built: Thu Sep 17 16:48:42 2009]
[opening typeerror.sml]
val suffixes = fn : 'a list -> 'a list list
typeerror.sml:17.81-17.93 Error: operator and operand don't agree [UBOUND match]
operator domain: 'a list * 'a list list
operand: 'a list * 'b list
in expression:
(x :: xs) :: acc
typeerror.sml:16.13-17.94 Error: types of rules don't agree [UBOUND match]
earlier rule(s): 'a list * 'Z list list -> 'Z list list
this rule: 'a list * 'b list -> 'Y
in rule:
(x :: xs : 'a list,acc : 'b list) =>
(suffixes_helper xs) ((x :: xs) :: acc)
/usr/local/smlnj-110.71/bin/sml: Fatal error -- Uncaught exception Error with 0
raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
There are two errors given. The latter seems to be less important here, a mismatch between the two clauses of suffixes_helper. The first is the one I don't understand. I annotate to state that the first param is of type 'a:list and that the second param is of type 'b:list. Should not the Hindley-Milner type inference algorithm, which is built of top of general unification as I understand it, be able to unify 'b:list with 'a:list list, using a substitution of 'b ---> 'a list?
EDIT: An answer suggests it may have something to do with the type inference algorithm disallowing inferred types which in some sense are more strict than the ones given by the type annotations. I would guess that such a rule would only apply to annotations on parameters and on a function as a whole. I have no idea if this is correct. In any case, I tried moving the type annotations over to the function body, and I get the same sort of error:
fun suffixes_helper [] acc = []::acc
| suffixes_helper (x::xs) acc =
suffixes_helper (xs:'a list) (((x::xs)::acc):'b list);
The error is now:
typeerror.sml:5.67-5.89 Error: expression doesn't match constraint [UBOUND match]
expression: 'a list list
constraint: 'b list
in expression:
(x :: xs) :: acc: 'b list
This works:
fun suffixes_tail xs =
let
fun suffixes_helper [] acc = []::acc
| suffixes_helper (x::xs:'a list) (acc:'a list list) =
suffixes_helper xs ((x::xs)::acc)
in
suffixes_helper xs []
end
As Joh and newacct say, 'b list is too loose. When you give the explicit type annotation
fun suffixes_helper (_ : 'a list) (_ : 'b list) = ...
it is implicitly quantified as
fun suffixes_helper (_ : (All 'a).'a list) (_ : (All 'b).'b list) = ...
and obviously 'b = 'a list cannot be true (All a') and (All b') simultaneously.
Without the explicit type annotation, type inference can do the right thing, which is to unify the types. And really, SML's type system is simple enough that (as far as I am aware) it is never undecidable, so explicit type annotations should never be necessary. Why do you want to put them in here?
When you use type variables like 'a and 'b, that means that 'a and 'b can be set to anything, independently. So for example it should work if I decided that 'b was int and 'a was float; but obviously that is not valid in this case because it turns out that 'b must be 'a list.
I am not sure about SML, but F#, another functional language, gives a warning in this kind of situation. Giving an error may be a bit harsh, but it makes sense: if the programmer introduces an extra type variable 'b, and if 'b must be of type 'a list, the function might not be as generic as the programmer intended, which is worth reporting.