I am trying to figure out what this function does, and when I run it in my code editor, it is giving me a syntax error at the "end in". I have tried putting brackets around "let x" and some other places, but I am at a loss. I would appreciate any help in understanding why I am getting an error.
let rec map (f: 'a -> 'b) (y: 'a list): 'b list =
begin match y with
| [] -> []
| h :: t -> (f h) :: (map f t)
end in
let x = map (fun t -> (t + 1) [0; 1; 2] in
0 :: x
Is this what you are trying to accomplish?
let () =
let rec map f y =
match y with
| [] -> []
| h :: t -> (f h) :: (map f t)
in
let x = map (fun t -> t + 1) [0; 1; 2] in
0 :: x
|> List.iter (fun x -> Printf.printf "%d\n" x)
Related
My goal here was to convert a (int * int) list to an int list. This is what I did:
let tuples_list_to_list l =
let rec aux_tuples_to_list acc l =
match l with
| [] -> acc
| x :: tl -> aux_tuples_to_list (fst x :: snd x :: acc) tl in
aux_tuples_to_list [] l
I was wondering if there was a more "elegant" even though this is subjective or at least better, way to write my function. I was thinking about using List.map or List.fold_left but I was having issues figuring out I could use those two functions to do the same thing I did. Basically, I think it would be possible to have a one-liner instead of the whole function I wrote.
What do you think? Thanks
This task is suited for List.concat_map (also known as "flat map" in some other languages):
(* List.concat_map : ('a -> 'b list) -> 'a list -> 'b list *)
let tuples_list_to_list l =
List.concat_map (fun (x, y) -> [x; y]) l
You can use List.fold_left, but you'll have to reverse the result at the end as the list is constructed in reverse order:
let tuples_list_to_list l =
List.rev (List.fold_left (fun acc (x, y) -> y :: x :: acc) [] l)
You can also deconstruct the tuple values in the pattern matching instead of using fst and snd (This version, unlike yours, gives a result list with the numbers in the same order as the orignal):
let tuples_list_to_list l =
let rec aux_tuples_to_list acc l =
match l with
| [] -> List.rev acc
| (x, y) :: tl -> aux_tuples_to_list (y :: x :: acc) tl in
aux_tuples_to_list [] l
Yet Another Option is using List.fold_right, which avoids the need to reverse the accumulator list at the end at the cost of not being tail recursive:
let tuples_list_to_list l =
List.fold_right (fun (x, y) acc -> x :: y :: acc) l [];;
A funky title perhaps, but I'm having a problem with the following:
Given a list of type (a * b) list, I want to create a new list with type (a * b list) list. An example:
Given list let testList = [(1,"c");(2,"a");(1,"b")], my function should return [(1, ["c";"b"]; (2, ["a"])].
I have the following, but I'm a little stuck on how to continue:
let rec toRel xs =
match xs with
| (a,b)::rest -> (a,[b])::toRel rest
| _ -> []
You can use the built-in function List.groupBy and then map to remove the redundant key:
testList |> List.groupBy fst |> List.map (fun (k,v) -> (k, List.map snd v))
// val it : (int * string list) list = [(1, ["c"; "b"]); (2, ["a"])]
Otherwise if you want to continue with a match you can do something like this:
let toRel x =
let rec loop acc xs =
match xs with
| (k, b) :: rest ->
let acc =
match Map.tryFind k acc with
| Some v -> Map.add k (b::v) acc
| None -> Map.add k [b] acc
loop acc rest
| _ -> acc
loop Map.empty x |> Map.toList
Or using Option.toList you can write it:
let toRel x =
let rec loop acc xs =
match xs with
| (k, b) :: rest ->
let acc =
let lst = Map.tryFind k acc |> Option.toList |> List.concat
Map.add k (b::lst) acc
loop acc rest
| _ -> acc
loop Map.empty x |> Map.toList
Hy, i'm trying to create a histogram but i keep getting an error.
Histogram example:
input :[2;1;2;3;2;1;2;2;5]
output :[(2,5);(1,2);(3,1);(5,1)]
My code:
let rec count a ls = match ls with
|[] -> 0
|x::xs when x=a -> 1 + count a xs
|_::xs -> count a xs
let rec histo l = match l with
|[] -> []
|x :: xs -> [(x, count x l)] # List.filter(fun x -> xs != x)histo xs;;
Error:
This function has type ('a -> bool) -> 'a list -> 'a list It is applied to too many arguments; maybe you forgot a `;'.
You are almost at the end ;)
Some hints :
take care of parenthesis (some are missing in your code).
your filter is not correct : (fun (t,_) -> not (t = x)) because histo returns a list of tuple.
let rec count a = function
|[] -> 0
|x::xs -> if x=a then 1 + count a xs else count a xs
let rec histo = function
|[] -> []
|x::xs -> let l'=List.filter ((<>)x) xs in
[(x, 1+count x xs)] # histo l'
;;
Test
# histo [2;1;2;3;2;1;2;2;5];;
- : (int * int) list = [(2, 5); (1, 2); (3, 1); (5, 1)]
Or
let rec histo = function
|[] -> []
|x::xs -> let l'=List.filter ((<>)x) xs in
[(x, 1+List.length xs - List.length l')] # histo l'
;;
How to implement insert using foldr in haskell.
I tried:
insert'' :: Ord a => a -> [a] -> [a]
insert'' e xs = foldr (\x -> \y -> if x<y then x:y else y:x) [e] xs
No dice.
I have to insert element e in list so that it goes before first element that is larger or equal to it.
Example:
insert'' 2.5 [1,2,3] => [1.0,2.0,2.5,3.0]
insert'' 2.5 [3,2,1] => [2.5,3.0,2.0,1.0]
insert'' 2 [1,2,1] => [1,2,2,1]
In last example first 2 is inserted one.
EDIT:
Thanks #Lee.
I have this now:
insert'' :: Ord a => a -> [a] -> [a]
insert'' e xs = insert2 e (reverse xs)
insert2 e = reverse . snd . foldr (\i (done, l) -> if (done == False) && (vj e i) then (True, e:i:l) else (done, i:l)) (False, [])
where vj e i = e<=i
But for this is not working:
insert'' 2 [1,3,2,3,3] => [1,3,2,2,3,3]
insert'' 2 [1,3,3,4] => [1,3,2,3,4]
insert'' 2 [4,3,2,1] => [4,2,3,2,1]
SOLUTION:
insert'' :: Ord a => a -> [a] -> [a]
insert'' x xs = foldr pom poc xs False
where
pom y f je
| je || x > y = y : f je
| otherwise = x : y : f True
poc True = []
poc _ = [x]
Thanks #Pedro Rodrigues (It just nedded to change x>=y to x>y.)
(How to mark this as answered?)
You need paramorphism for that:
para :: (a -> [a] -> r -> r) -> r -> [a] -> r
foldr :: (a -> r -> r) -> r -> [a] -> r
para c n (x : xs) = c x xs (para c n xs)
foldr c n (x : xs) = c x (foldr c n xs)
para _ n [] = n
foldr _ n [] = n
with it,
insert v xs = para (\x xs r -> if v <= x then (v:x:xs) else (x:r)) [v] xs
We can imitate paramorphisms with foldr over init . tails, as can be seen here: Need to partition a list into lists based on breaks in ascending order of elements (Haskell).
Thus the solution is
import Data.List (tails)
insert v xs = foldr g [v] (init $ tails xs)
where
g xs#(x:_) r | v <= x = v : xs
| otherwise = x : r
Another way to encode paramorphisms is by a chain of functions, as seen in the answer by Pedro Rodrigues, to arrange for the left-to-right information flow while passing a second copy of the input list itself as an argument (replicating the effect of tails):
insert v xs = foldr g (\ _ -> [v]) xs xs
where
g x r xs | v > x = x : r (tail xs) -- xs =#= (x:_)
| otherwise = v : xs
-- visual aid to how this works, for a list [a,b,c,d]:
-- g a (g b (g c (g d (\ _ -> [v])))) [a,b,c,d]
Unlike the version in his answer, this does not copy the rest of the list structure after the insertion point (which is possible because of paramorphism's "eating the cake and having it too").
Here's my take at it:
insert :: Ord a => a -> [a] -> [a]
insert x xs = foldr aux initial xs False
where
aux y f done
| done || x > y = y : f done
| otherwise = x : y : f True
initial True = []
initial _ = [x]
However IMHO using foldr is not the best fit for this problem, and for me the following solution is easier to understand:
insert :: Int -> [Int] -> [Int]
insert x [] = [x]
insert x z#(y : ys)
| x <= y = x : z
| otherwise = y : insert x ys
I suppose fold isn't handy here. It always processes all elements of list, but you need to stop then first occurence was found.
Of course it is possible, but you probable don't want to use this:
insert' l a = snd $ foldl (\(done, l') b -> if done then (True, l'++[b]) else if a<b then (False, l'++[b]) else (True, l'++[a,b])) (False, []) l
I'm trying to make a recursive function to get the transpose of a list of lists, n x p to p x n. But i'm unable to do so. I've been able to make a function to transpose a 3 x n list of lists to an n x 3 one:
let rec drop1 list=
[(match (List.nth list 0) with [] -> [] | a::b -> b);
(match (List.nth list 1) with [] -> [] | a::b -> b);
(match (List.nth list 2) with [] -> [] | a::b -> b);]
let rec transpose list=
if List.length (List.nth list 0) == 0 then []
else [(match (List.nth list 0) with [] -> 0 | a::b -> a);
(match (List.nth list 1) with [] -> 0 | a::b -> a);
(match (List.nth list 2) with [] -> 0 | a::b -> a)]
:: transpose (drop1 list)
But I'm not able to generalize it. I'm surely thinking in the wrong direction. Is this generalizable? Is there a better solution? Please help.
let rec transpose list = match list with
| [] -> []
| [] :: xss -> transpose xss
| (x::xs) :: xss ->
(x :: List.map List.hd xss) :: transpose (xs :: List.map List.tl xss)
Taking advantage of syntax changes since answer first posted:
let rec transpose list = match list with
| [] -> []
| [] :: xss -> transpose xss
| (x::xs) :: xss ->
List.(
(x :: map hd xss) :: transpose (xs :: map tl xss)
)
I know this is an old question, but I recently had to solve this as part of an exercise I was doing, and I came across #sepp2k's solution, but I couldn't understand how it worked, so I tried to arrive at it by myself.
This is essentially the same algorithm, but a little bit more terse, as it does not destructure the list of lists. I thought I would post it here in case anyone else is searching, and might find this way of expressing it useful:
let rec transpose = function
| []
| [] :: _ -> []
| rows ->
List.map List.hd rows :: transpose (List.map List.tl rows)
Assuming the matrix is rectangular (otherwise Invalid_argument "map2" will be raised):
let transpose m =
if m = [] then [] else
List.(fold_right (map2 cons) m ## map (fun _ -> []) (hd m))
Note that map (fun _ -> []) (hd m) just creates a list of empty lists, of length equal to the number of columns in m.
So a clearer representation of this code would be:
let transpose m =
if m = [] then [] else
let open List in
let empty_rows = map (fun _ -> []) (hd m) in
fold_right (map2 cons) m empty_rows