I am new to Ocaml and am writing code to substitute elements in nested Ocaml lists. My code is as follows:
type 'a sexp = S of 'a | L of 'a sexp list
My substitution function(it replaces all occurrences of element a with b in nested lists) is as follows:
let rec subst a b list = match list with
| [] -> list
| S s :: t -> if s = a then (S b) :: (subst a b t) else (S s) :: (subst a b t)
| L l :: t -> (subst a b l) :: (subst a b t)
Despite multiple attempts(for nearly 6 hours), I have not been able to compile this code.. Please help!
Can I suggest to first write a function subst of type 'a -> 'a -> 'a sexp -> 'a sexp instead? It would read
let subst x y sexp =
let rec visit = function
| S z -> S (if z = x then y else z)
| L sexps -> L (List.map visit sexps)
in
visit sexp
and arguably nicely and idiomatically captures the idea of recursing over an sexp.
Now, to obtain a function to operate on lists rather than single sexps, you can easily define a function subst_list of type 'a -> 'a -> 'a sexp list -> 'a sexp list:
let subst_list x y sexps = List.map (subst x y) sexps
Even nicer is to abstract away from substitution and have a more generally applicable function map of type ('a -> 'b) -> 'a sexp -> 'b sexp for performing structure-preserving mappings of sexps:
let map f sexp =
let rec visit = function
| S x -> S (f x)
| L sexps -> L (List.map visit sexps)
in
visit sexp
And then define subst in terms of map and subst_list, as before, in terms of subst:
let subst x y sexp = map (fun z -> if z = x then y else z) sexp
let subst_list x y sexps = List.map (subst x y) sexps
Note: using an F# compiler here; I don't have an OCaml compiler on this computer.
The last line of your subst function has an error: It should be as follows:
| L l :: t -> L (subst a b l) :: (subst a b t)
So the complete code would look like this:
type 'a Sexp =
| S of 'a
| L of 'a Sexp list
let rec subst (a) (b) (lst : 'a Sexp list) =
match lst with
| [] -> lst
| S s :: t -> if s = a then (S b) :: (subst a b t) else (S s) :: (subst a b t)
| L l :: t -> L (subst a b l) :: (subst a b t)
let test () =
let (lst : int Sexp list) = [S 1; L [S 2; L [S 3]; S 4]; S 5]
let a = 2
let b = 3
subst a b lst
The output of test() is
[S 1; L [S 3; L [S 3]; S 4]; S 5]
The reason is that your function subst returns a 'a Sexp list. If you omit the L constructor from the last line, then subst a b l is of type 'a Sexp list, which you are attempting to cons with another list of type 'a Sexp list. This does not work.
Nor was this your intention, since you wanted to end up with an entity of type 'a Sexp list, which means you must cons an element of type 'a Sexp with a list of type 'a Sexp list. By specifying the L constructor, you are creating an element of type 'a Sexp list, which you can now cons with the rest of the list.
It looks like your function subst is supposed to return something of type 'a sexp list. That's what the first and second match cases return.
In the third match case, then, your returned value is:
(subst a b l) :: (subst a b t)
Since your function returns 'a sexp list, this type doesn't make a lot of sense. The head of the list is of type 'a sexp list and the tail of the list is also of type 'a sexp list. It's very difficult to come up with any lists that have this kind of structure. I think what you want is for the head of the list to be of type 'a sexp.
If you want the head of the list to be of type 'a sexp, you need some way of packaging up a list of things into a single 'a sexp. If this isn't enough of a hint, look at your L constructor. That's exactly what it does.
Related
let rec fold_inorder f acc t =
match t with
| Leaf -> acc
| Node (l, n, r) -> f (fold_inorder f acc l) (f n (fold_inorder f acc r))
I'm trying to print the infold of a tree as following :
fold_inorder (fun acc x -> acc # [x]) [] (Node (Node (Leaf,1,Leaf), 2, Node (Leaf,3,Leaf))) = [1;2;3]
I'm getting an error saying my [x] is
This expression has type 'a list
but an expression was expected of type 'a
The type variable 'a occurs inside 'a list
I'm really not sure what to do from here. Can anyone nudge me in the right direction?
In your definition of fold_inorder, what type do you expect f to have?
If I look at this call:
f n (fold_inorder f acc r)
it appears that the first parameter of f is a new value from a tree node and the second parameter is an accumulated value.
But in your test call you define f like this:
(fun acc x -> ...)
This suggests that the first parameter is the accumulated value and the second parameter is a new value from a tree node.
Lets say I have a list of functions
let plus_one (x: int) : int = x + 1 in
let double (x: int) : int = x * 2 in
let square (x: int) : int = x * x in
let fun_list = [square, double, plus_one] ;;
Using fold, I want to take this list of functions and combine them into a single function. Something like,
let combined (x: int) : int = x * (2 * (x + 1))
This is what I have:
let combine_functions (fun_list : ('a -> 'a) list) : ('a -> 'a) =
List.fold_right (fun f acc -> f acc) fun_list (fun x -> x)
;;
I would think this would work, however when I try to run this, it tells me that this expression has type 'a -> 'a when it should have type ('a -> 'a) -> ('a -> 'a)
I've solved this by changing the second line of code from
List.fold_right (fun f acc -> f acc) fun_list (fun x -> x)
to
List.fold_right (fun f acc -> (fun x -> f (acc x))) fun_list (fun x -> x)
I'm a bit unclear on what sort of combination you want, do you mean functional composition? If that's the case, then your combined function would look something like this:
square (double (plus_one x))
or
((x + 1) * 2) * ((x + 1) * 2)
which could be achieved by the function
let combine_functions ls =
List.fold_right (fun f x -> f x) ls;;
However I'm not totally sure if this is really what you're trying to do. As an aside, you don't need to explicitly type all your OCaml code, and I personally find that I'm more productive when I let the type inference do it for me.
Is there a way, to write a polymorphic function (in sml), that calls itself with arguments of different type than the arguments it has got?
For example, I was looking on this answer, (it has the declaration datatype ('a,'b)alterlist = Nil| element of 'a*('b,'a)alterlist;) and intuitively, I would like to implement the function unzip, as:
fun unzip Nil = ([],[]) |
unzip (element(x,l)) = let val (b,a)=unzip l in (x::a,b) end;
The type inference system understands it as ('a,'a) alterlist -> 'a list * 'a list, but I want something of type ('a,'b) alterlist -> 'a list * 'b list (such that the inner call is to a ('b,'a) alterlist -> 'b list * 'a list)
I believe what you are asking for is polymorphic recursion, which is not implemented in standard ML.
This is however implemented in Haskell (and as #seanmcl pointed out, ocaml):
import Prelude hiding(unzip)
data Alterlist a b = Nil | Elem a (Alterlist b a)
unzip :: Alterlist a b -> ([a], [b])
unzip Nil = ([], [])
unzip (Elem x l) =
let (b, a) = unzip l
in (x : a, b)
x = Elem 1 (Elem True (Elem 5 (Elem False Nil)))
*Main> unzip x
([1,5],[True,False])
Consider a recursive function, say the Euclid algorithm defined by:
let rec gcd a b =
let (q, r) = (a / b, a mod b) in
if r = 0 then b else gcd b r
(This is a simplified, very brittle definition.) How to memoize such a function? The classical approach of defining a high-order function memoize : ('a -> 'b) -> ('a -> 'b)
adding memoization to the function is here useless, because it will only save time on the first call.
I have found details on how to memoize such function in Lisp or Haskell:
How do I memoize a recursive function in Lisp?
Memoization with recursion
These suggestions rely on the ability found in Lisp to overwrite the symbol definition of a function or on the “call-by-need” strategy used by Haskell, and are therefore useless in OCaml.
The winning strategy is to define the recursive function to be memoized in a continuation passing style:
let gcd_cont k (a,b) =
let (q, r) = (a / b, a mod b) in
if r = 0 then b else k (b,r)
Instead of defining recursively the gcd_cont function, we add an argument, the “continuation” to be called in lieu of recursing. Now we define two higher-order functions, call and memo which operate on functions having a continuation argument. The first function, call is defined as:
let call f =
let rec g x =
f g x
in
g
It builds a function g which does nothing special but calls f. The second function memo builds a function g implementing memoization:
let memo f =
let table = ref [] in
let compute k x =
let y = f k x in
table := (x,y) :: !table; y
in
let rec g x =
try List.assoc x !table
with Not_found -> compute g x
in
g
These functions have the following signatures.
val call : (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b = <fun>
val memo : (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b = <fun>
Now we define two versions of the gcd function, the first one without memoization and the second one with memoization:
let gcd_call a b =
call gcd_cont (a,b)
let gcd_memo a b =
memo gcd_cont (a,b)
# let memoize f =
let table = Hashtbl.Poly.create () in
(fun x ->
match Hashtbl.find table x with
| Some y -> y
| None ->
let y = f x in
Hashtbl.add_exn table ~key:x ~data:y;
y
);;
val memoize : ('a -> 'b) -> 'a -> 'b = <fun>
# let memo_rec f_norec x =
let fref = ref (fun _ -> assert false) in
let f = memoize (fun x -> f_norec !fref x) in
fref := f;
f x
;;
val memo_rec : (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b = <fun>
You should read the section here: https://realworldocaml.org/v1/en/html/imperative-programming-1.html#memoization-and-dynamic-programming in the book Real World OCaml.
It will help you truly understand how memo is working.
I am new to Ocaml and want help with recursive function defined on a recursive data type. I have defined a data type as follows
type 'a slist = S of 'a sexp list
and
'a sexp = Symbol of 'a | L of 'a slist
The function(subst) I'm writing checks for a symbol a in the defined slist and substitutes it by b. For ex subst 1 10 S[ 1; 4; S[L[3; 1;]; 3];] returns S[10; 4; S[L[S[3; 10;]]; 3;]
. My code is as follows
let rec subst a b sl = match sl with
S s -> match s with
[] -> []
| p :: q -> match p with
Symbol sym -> if sym = a then S[b] :: (**subst** a b S[q]) else
S[p] :: (subst a b S[q])
L l -> (subst a b l) :: (subst a b S[q])
| L lis -> subst a b lis;;
I am getting the error :
This function is applied to too many arguments; Maybe you forgot a ';'
Please help
Your type can be defined in a simpler way, you don't need slist:
type 'a sexp = Symbol of 'a | L of 'a sexp list
Your problem is that subst a b S[q] is read as subst a b S [q], that is the function subst applied to 4 arguments. You must write subst a b (S[q]) instead.