I am currently doing a custom version of List.flatten and I blocked at one place.
I currently have:
let rec doflatten (ls:int list list) (flatList: int list) : int list =
match ls with
| [] -> flatList
| hd :: tl -> (doflatten (List.tl(ls)) (List.hd(hd) :: flatList))
currently this compiles, but when I call the function, it gives me a "failure hd". It is suppose to do something like:
doflatten [[1;2;4]; []; [9]; [5;6]] [] = [1;2;4;9;5;6]
You are working with a list of lists, so in this pattern:
| hd :: tl -> ...
the head hd is a list.
However, hd can be the empty list. Your code doesn't handle this case properly. You just need to decide what you want to do.
You can have an extra pattern like this:
| [] :: tl ->
this pattern will match the case in question.
Related
let rec some_none list =
match list with
| [] -> list
| hd::tl ->
if hd = 0 then
[None] # some_none tl
else
[Some hd] # some_none tl;;
When I run this program it returns
Error: This expression has type int list but an expression was expected of type
'a option list
Type int is not compatible with type 'a option
How can I make it so that I am able to change a regular a' list to a' option list?
These two lines
match list with
| [] -> list
imply that the list returned by some_none has the same type as its argument.
Changing that line to
| [] -> []
solves the issue, since the left-hand and right-hand side are now unrelated.
A more subtle way (and not really useful here) is to use the as construct,
| [] as x -> x
because ... as x construct captures the type of the pattern rather than the type of the scrutinee (here list). However, this construction is mostly useful with polymorphic variants.
Also notice that your function some_none change neither the length of the list nor the order of the elements of the list. This means that it can be written as a map:
let some_none = List.map (fun elt -> ... )
Adding to what octachron has already said, there's a few style and performance issues with your code too.
First, it's unnecessary to create a new list in order to concatenate it using # when :: exists to prepend a single element to a list:
let rec some_none list =
match list with
| [] -> []
| hd::tl ->
if hd = 0 then
None :: some_none tl
else
Some hd :: some_none tl
Second, you can match on literal patterns directly instead of using comparison in an if expression within the branch:
let rec some_none list =
match list with
| [] -> []
| 0::tl -> None :: some_none tl
| hd::tl -> Some hd :: some_none tl
Third, you can use function to match directly on the last function argument:
let rec some_none = function
| [] -> []
| 0::tl -> None :: some_none tl
| hd::tl -> Some hd :: some_none tl
And fourth, you can use List.map to transform elements individually:
let some_none =
List.map (function 0 -> None | x -> Some x)
And now you have a function that is suddenly much easier to read and understand fully.
I created a function that insert one element in a list.
The insertion will happens when the element i is equal to k.
The list is a list of (int * string) list , like [(1,"hi")...]
The idea is to create a new list where for each iteration hd is append at the beginning.
When i is found then k is inserted and the function stops.
Here the code :
let rec insert k v list_ =
let rec support k v list _
match list_ with
| (i,value) when i = k -> (k,v) :: tl
| hd :: [] -> hd
| hd :: tl -> hd :: support k v tl in
let inserted = support k v list_
let () =
let k = [ (1,"ciao");(2,"Hola");(3,"Salut") ] in
insert 2 "Aufwidersen" k
I think all is fine but the compiler said :
5 | | hd :: [] -> hd
Error: This pattern matches values of type 'a list
but a pattern was expected which matches values of type 'b * 'c`
And I don't understand why, I think all is ok.
The problem is this part:
match list_ with
| (i,value) -> ...
When you write this, Ocaml infers that list_ has to be a tuple, which is a type error because it is actually a list of tuples.
I didn't understand exactly what you want the insert function but the typical pattern is to have two cases, one for the empty list and one for the non-empty list. I personally prefer using if-then-else instead of pattern guards but if you want to use pattern guards that should also work. Either way, you certainly want to cover the case of the empty list.
match list_ with
| [] -> (* ... *)
| (i,value)::tl ->
if i = k then
(* ... *)
else
(* ... *)
I am very new to F# and functional programming in general, and would like to recursively create a function that takes a list, and doubles all elements.
This is what I used to search for a spacific element, but im not sure how exactly I can change it to do what I need.
let rec returnN n theList =
match n, theList with
| 0, (head::_) -> head
| _, (_::theList') -> returnN (n - 1) theList'
| _, [] -> invalidArg "n" "n is larger then list length"
let list1 = [5; 10; 15; 20; 50; 25; 30]
printfn "%d" (returnN 3 list1 )
Is there a way for me to augment this to do what I need to?
I would like to take you through the thinking process.
Step 1. I need a recursive function that takes a list and doubles all the elements:
So, let's implement this in a naive way:
let rec doubleAll list =
match list with
| [] -> []
| hd :: tl -> hd * 2 :: doubleAll tl
Hopefully this logic is quite simple:
If we have an empty list, we return another empty list.
If we have a list with at least one element, we double the element and then prepend that to the result of calling the doubleAll function on the tail of the list.
Step 2. Actually, there are two things going on here:
I want a function that lets me apply another function to each element of a list.
In this case, I want that function to be "multiply by 2".
So, now we have two functions, let's do a simple implementation like this:
let rec map f list =
match list with
| [] -> []
| hd :: tl -> f hd :: map f tl
let doubleAll list = map (fun x -> x * 2) list
Step 3. Actually, the idea of map is such a common one that it's already built into the F# standard library, see List.map
So, all we need to do is this:
let doubleAll list = List.map (fun x -> x * 2) list
I'm trying to implement a RLE decoder for a game, and it works, but I'd like to shrink the code a bit, but I can't figure out how to put List.append and the repeat and rleExpand calls on one line
The signature of List.append is List.append : 'T list -> 'T list -> 'T list, so obviously I cannot just do
List.append(repeat(pattern,count), rleExpand(tail,rleTag)) - but would like to know how to do that. I also can use the # operator - maybe that's the most readable one. But how do I use List.append if my lists are created by a function application like in the listing below?
let rec repeat(item,count) =
match count with
| 0 -> []
| n -> item :: repeat(item,n-1)
let rec rleExpand(packed, rleTag: int) =
match packed with
| [] -> []
| tag :: count :: pattern :: tail when tag = rleTag ->
let repeated = repeat(pattern,count)
let rest = rleExpand(tail,rleTag)
List.append repeated rest
| head :: tail -> head :: rleExpand(tail,rleTag)
I would probably write:
repeat(pattern,count) # rleExpand(tail,rleTag)
But you can also write
List.append (repeat(pattern,count)) (rleExpand(tail,rleTag))
You cannot use List.append(repeat(pattern,count), rleExpand(tail,rleTag)) as you originally suggested because List.append takes curried (rather than tupled) arguments.
Does something like this work?
let repeat(item, count) = [for i in 1 .. count -> item]
let rec rleExpand(packed, rleTag: int) =
match packed with
| [] -> []
| tag :: count :: pattern :: tail when tag = rleTag ->
List.collect id [repeat(pattern,count); rleExpand(tail,rleTag)]
| head :: tail -> head :: rleExpand(tail,rleTag)
It's also more commonplace to use make functions curryable by not using tuples as parameters.
I'm working with a list of lists in OCaml, and I'm trying to write a function that combines all of the lists that share the same head. This is what I have so far, and I make use of the List.hd built-in function, but not surprisingly, I'm getting the failure "hd" error:
let rec combineSameHead list nlist = match list with
| [] -> []#nlist
| h::t -> if List.hd h = List.hd (List.hd t)
then combineSameHead t nlist#uniq(h#(List.hd t))
else combineSameHead t nlist#h;;
So for example, if I have this list:
[[Sentence; Quiet]; [Sentence; Grunt]; [Sentence; Shout]]
I want to combine it into:
[[Sentence; Quiet; Grunt; Shout]]
The function uniq I wrote just removes all duplicates within a list. Please let me know how I would go about completing this. Thanks in advance!
For one thing, I generally avoid functions like List.hd, as pattern maching is usually clearer and less error-prone. In this case, your if can be replaced with guarded patterns (a when clause after the pattern). I think what is happening to cause your error is that your code fails when t is []; guarded patterns help avoid this by making the cases more explicit. So, you can do (x::xs)::(y::ys)::t when x = y as a clause in your match expression to check that the heads of the first two elements of the list are the same. It's not uncommon in OCaml to have several successive patterns which are identical except for guards.
Further things: you don't need []#nlist - it's the same as just writing nlist.
Also, it looks like your nlist#h and similar expressions are trying to concatenate lists before passing them to the recursive call; in OCaml, however, function application binds more tightly than any operator, so it actually appends the result of the recursive call to h.
I don't, off-hand, have a correct version of the function. But I would start by writing it with guarded patterns, and then see how far that gets you in working it out.
Your intended operation has a simple recursive description: recursively process the tail of your list, then perform an "insert" operation with the head which looks for a list that begins with the same head and, if found, inserts all elements but the head, and otherwise appends it at the end. You can then reverse the result to get your intended list of list.
In OCaml, this algorithm would look like this:
let process list =
let rec insert (head,tail) = function
| [] -> head :: tail
| h :: t ->
match h with
| hh :: tt when hh = head -> (hh :: (tail # t)) :: t
| _ -> h :: insert (head,tail) t
in
let rec aux = function
| [] -> []
| [] :: t -> aux t
| (head :: tail) :: t -> insert (head,tail) (aux t)
in
List.rev (aux list)
Consider using a Map or a hash table to keep track of the heads and the elements found for each head. The nlist auxiliary list isn't very helpful if lists with the same heads aren't adjacent, as in this example:
# combineSameHead [["A"; "a0"; "a1"]; ["B"; "b0"]; ["A"; "a2"]]
- : list (list string) = [["A"; "a0"; "a1"; "a2"]; ["B"; "b0"]]
I probably would have done something along the lines of what antonakos suggested. It would totally avoid the O(n) cost of searching in a list. You may also find that using a StringSet.t StringMap.t be easier on further processing. Of course, readability is paramount, and I still find this hold under that criteria.
module OrderedString =
struct
type t = string
let compare = Pervasives.compare
end
module StringMap = Map.Make (OrderedString)
module StringSet = Set.Make (OrderedString)
let merge_same_heads lsts =
let add_single map = function
| hd::tl when StringMap.mem hd map ->
let set = StringMap.find hd map in
let set = List.fold_right StringSet.add tl set in
StringMap.add hd set map
| hd::tl ->
let set = List.fold_right StringSet.add tl StringSet.empty in
StringMap.add hd set map
| [] ->
map
in
let map = List.fold_left add_single StringMap.empty lsts in
StringMap.fold (fun k v acc-> (k::(StringSet.elements v))::acc) map []
You can do a lot just using the standard library:
(* compares the head of a list to a supplied value. Used to partition a lists of lists *)
let partPred x = function h::_ -> h = x
| _ -> false
let rec combineHeads = function [] -> []
| []::t -> combineHeads t (* skip empty lists *)
| (hh::_ as h)::t -> let r, l = List.partition (partPred hh) t in (* split into lists with the same head as the first, and lists with different heads *)
(List.fold_left (fun x y -> x # (List.tl y)) h r)::(combineHeads l) (* combine all the lists with the same head, then recurse on the remaining lists *)
combineHeads [[1;2;3];[1;4;5;];[2;3;4];[1];[1;5;7];[2;5];[3;4;6]];;
- : int list list = [[1; 2; 3; 4; 5; 5; 7]; [2; 3; 4; 5]; [3; 4; 6]]
This won't be fast (partition, fold_left and concat are all O(n)) however.