Suppose I have this function, in pseudo-code, that reverse a list:
def function reverse( list ) :
if ( empty(list) )
return empty_list;
else
return append(
reverse( list(2, lenght) ,
list(1)));
This code is not tail-recursive;
how can i make it tail-recursive?
See: Tail Call
For F#
let map f l =
let rec loop acc = function
| [] -> List.rev acc
| x::xs -> loop (f x::acc) xs
loop [] l
For reversing a string
Related
Suppose I have the following tree type:
type T<'a> = N of 'a * T<'a> list
How do I declare a recursive map function for it? Currently I have this, but it's an infinite loop:
let rec map f (N(a,sbs)) =
match sbs with
| [] -> N(f a,[])
| sbs' -> map f (N(a,sbs'))
I'd appreciate a hint.
Here's a hint. It's a tail-recursive map function.
let mapTR f l =
let rec loop acc = function
| [] -> List.rev acc
| x::xs -> loop (f x::acc) xs
loop [] l
I set myself the following challenge (and failed):
I want to write a map functional, map f lofls, that takes a function, f 'a -> 'b and a list of lists, lofls 'a list list and applies the function f on every element of the list of lists. The constraint that I added is that I am not allowed to used nested maps for lists, and I have to do it recursively.
I tried to do it in F# but any language should do. Any ideas?
Edit
Here is my attempt (which works but is ugly and I am not a fan of the use of rev either . . .)
let map f lis =
let rec map2 f lis aux =
match (lis, aux) with
|([], []) -> []
|([], aux) -> [aux]
|(hd::tl, aux) ->
match hd with
|[] -> (List.rev aux) :: (map2 f tl [])
|x::xs -> map2 f (xs::tl) ( (f x) :: aux )
map2 f lis []
(I also realised that this has been posted in a more concise form already)
Lets go step by step, from simple to complex.
This is the signature that you want your map function to have:
('a -> 'b) -> 'a list list -> 'b list list
The simple solution is this:
let map0 (f:'a -> 'b) (lofls:'a list list) : 'b list list = lofls |> List.map (List.map f)
But that one is not recursive and it uses nested maps.
A recursive solution could be this:
let rec map1 (f:'a -> 'b) (lofls:'a list list) : 'b list list =
match lofls with
| [] -> []
| l::rest -> (List.map f l) :: map1 f rest
It is recursive although it is still calling List.map in there.
So, here is the next level:
let rec map (f:'a -> 'b) (lofls:'a list list) : 'b list list =
match lofls with
| [ ] -> [ ]
| [ ] :: rest -> [ ] :: (rest |> map f)
| ( e::restl ) :: rest ->
match restl :: rest |> map f with
| [ ] -> [ ]
| [ ] :: rest -> [ f e ] :: rest
| ( restl ) :: rest -> ( f e :: restl ) :: rest
Another way:
let rec mapNested f lofls =
match lofls with
| [] -> []
| h::t -> (map f h) :: (mapNested f t)
and map f lst =
match lst with
| [] -> []
| h::t -> (f h) :: (map f t)
If this were a homework question, which I am sure it is not, the answer depends on what constitutes "a nested map for lists".
A construct like map [] (map [] f) can be rewritten with pipelining as f |> map [] |> map [], or with the function composition operator as (map [] >> map []) f, but may be still considered a nested map.
let mapNested f =
let rec map acc g = function
| [] -> List.rev acc
| x::xs -> map (g x::acc) g xs
f |> map [] |> map []
// val mapNested : f:('a -> 'b) -> ('a list list -> 'b list list)
This is the opportunity to demonstrate your grasp of lambda calculus and the Y combinator. Nested passing of the map function as an argument should clearly pass muster.
let rec Y f x = f (Y f) x
let map f acc g = function
| [] -> List.rev acc
| x::xs -> f (g x::acc) g xs
let map1 f =
Y map [] f
// val map1 : f:('a -> 'b) -> ('a list -> 'b list)
let map2 f =
Y map [] f
|> Y map []
// val map2 : f:('a -> 'b) -> ('a list list -> 'b list list)
A tail recursive way
let mapNested f lofls =
let rec map f lst acc =
match lst with
| [] -> List.rev acc
| h::t -> map f t (f h :: acc)
map (fun x -> map f x []) lofls []
I'm not sure why this question is tagged with SML, but since it is, here is how it can be done in SML:
First, this is the idiomatic solution that you're explicitly avoiding:
fun mapmap f = map (map f)
(You could write val mapmap = map o map if it weren't for ML's value restriction.)
And if you'd like to write mapmap using explicit recursion:
fun mapmap f [] = []
| mapmap f (xs::xss) = map f xs :: mapmap f xss
and map f [] = []
| map f (x::xs) = f x :: map f xs
One reason behind why this function is hard to write with a single explicitly recursive function is that the call stack is used for two things:
Collecting the result of each inner list, and
Collecting the result of the outer list.
One of those uses of the call stack can be turned into an explicit stack in an accumulating argument. This is how e.g. a tail-recursive rev is defined:
fun rev xs =
let fun aux [] acc = acc
| aux (x::xs) acc = aux xs (x::acc)
in aux xs [] end
The accumulating argument similarly isn't needed in the interface to mapmap, so it can be hidden in an inner helper function. So a single function that performs explicit recursion on both the inner and the outer list is complicated by this explicit bookkeeping:
fun mapmap f xss =
let fun aux f [] _ = []
| aux f ([]::xss) ys = rev ys :: aux f xss []
| aux f ((x::xs)::xss) ys = aux f (xs::xss) (f x :: ys)
in aux f xss [] end
I have this quite simple function which takes an int and adds it to the head of the list and is recursively called with i multiplied with itself:
let rec f i = function
| [] -> []
| x::xs -> (x+i)::f (i*i) xs
f 2 [1;2;3]
val it : int list = [3; 6; 19]
Now, I'm attempting to rewrite it using a continuation, but I'm a little stuck. Here's what I've come up with so far:
let fC i l =
let rec loop cont = function
| [] -> []
| x::xs -> cont(x+i)::loop (fun acc -> (acc*acc)) xs
loop id l
fC 2 [1;2;3] //Expected [3;6;19]
val it : int list = [3; 16; 25]
Any hints to what I'm doing wrong?
Looking at this questions and the comments it seems to me that there is some confusion.
Tail recursive does not necessary mean continuation passing style (CPS).
Here's the function in CPS:
let f' i p =
let rec loop i p k =
match p with
| [] -> k []
| x::xs -> loop (i*i) xs (fun a -> k ((x+i)::a))
loop i p id
And of course, it's tail recursive. But you can also write it tail recursive by using an accumulator instead of a continuation:
let f'' i p =
let rec loop i p acc =
match p with
| [] -> acc
| x::xs -> loop (i*i) xs ((x+i)::acc)
loop i p [] |> List.rev
See also the answer to this question to understand better CPS.
I'm trying to write a function that would take an input like :
repeat 3 [1;2] ;;
and display something like:
[1;2;1;2;1;2]
Now the code I have is:
let repeat ls n =
let rec helper acc n l =
if n = 0 then acc else helper (l :: acc) (n-1) l in
let rec helper2 acc = function
| [] -> acc
| h :: t -> helper2 (helper acc n h) t in helper2 [] (List.rev ls);;
which gives me an output of:
[1;1;1;2;2;2]
for the same input. What can I do to fix this?
You are almost at the end ;)
Just modify the first helper :
let rec helper acc n l =
if n = 0 then acc else helper (l # acc) (n-1) l ;;
And you will be close to the solution.
(you just want to replicate the input list so # is ok to concatenate this list to the acc, you do not want to parse each and every element of the list, so :: is not what you need)
I think this solution may be a little bit faster in term of complexity (and simplicity):
let repeat ls n =
let rec f l = function
| 0 -> l
| n -> f (List.rev_append ls l) (n-1) in
List.rev (f [] n)
Also I always forget if List.rev is a tail-recursive or not, so this may be even better:
let repeat ls n =
let rec rev l = function
| [] -> l
| a::t -> rev (a::l) t in
let rec f l = function
| 0 -> l
| n -> f (List.rev_append ls l) (n-1) in
rev [] (f [] n)
Note: in my opinion Pierre's answer is good enough, my post is more like remark.
I think I want it be be of type 'a list * 'a list -> 'a list .
intersection should return the intersection of two lists
sample input and output:
intersection ([1],[1]);
[1]
intersection ([1,2,3],[1,2]);
[1,2]
intersection ([[2,3],[1,2],[2,3]], [[1],[2,3]]);
[[2,3]]
my function:
fun intersection (l1, l2) = let
fun intersection_acc (acc, [], h::t) = []
| intersection_acc (acc, h::t, []) = []
| intersection_acc (acc, h::t, h2::t2) = if in_list (h, l2)
then intersection_acc (h::acc, t, l2)
else intersection_acc (acc, t, l2)
in intersection_acc ([], l1, l2)
end
I don't think in_list is the problem, but that looks like this:
fun in_list (x, []) = false
| in_list (x, y::r) = if x = y
then true
else in_list (x, r);
My guess is that you botched the base case in your accumulator function
intersection_acc (acc, h::t, []) = []
it should probably return something depending on acc:
intersection_acc (acc, h::t, []) = acc
The reason the 'b list shows up is because intersection will always return the empty list []. Since you don't use that empty list the compiler needs to be conservative and say that the list could be of any type.
In any case, your function seems to be fundamentally more confused. You actually want to do something like
result = []
for each item in list1:
if item in list2:
add item to result
return result
Translating this imperative code to a recursive function with an accumulator parameter:
fun go(acc, []) = acc
| go(acc, x::xs) =
if x in list2 then
go(x::acc, xs)
else
go(acc, xs)
For the full function:
fun intersect(list1, list2) = let
fun go(acc, []) = acc
| go(acc, x::xs) =
if x in list2 then
go(x::acc, xs)
else
go(acc, xs)
in go([], list1)