I am trying to learn F#, and I'm trying to create some simple functions as part of this learning.
I have created a function that adds an item to a list then reverses the result. This works very nicely in the F# interactive window in Visual Studio
let addThenReverse n list =
match list with
| [] -> []
| _ -> n::list |> List.rev
addThenReverse 0 [1;2;3] //results in [3; 2; 1; 0]
But I'm having difficulty with writing a function that would reverse a list then add an item to it.
let reverseThenAdd n list =
match list with
| [] -> []
| _ -> List.rev list |> n::list
reverseThenAdd 9 [1;2;3] //desired result [3; 2; 1; 9]
EDIT
The desired result for the above should be [9; 3; 2; 1]. Well done to those who spotted this!
This second function does not compile and I receive the warning 'This expression was expected to have type 'a list -> 'b list but here has type 'c list'
Any variants I try seem to result other compilation errors. I assume (but don't know how) that I need to use the new list created as a result of 'List.rev list', perhaps by assigning it to a variable.
The issue is that you are passing the reversed list to a concatenation expression, and that throws off the compiler. You should do:
let reverseThenAdd n list =
match list with
| [] -> []
| _ -> n :: (List.rev list)
reverseThenAdd 9 [1;2;3] //desired result [3;2;1;9]
which means that you are adding n to the list resulting from (List.rev list)
I'm a little confused by your desired results. Luiso has a version of your code that will fix the compiler, but it won't fit your desired result. With
let reverseThenAdd n list =
match list with
| [] -> []
| _ -> n :: (List.rev list)
reverseThenAdd 9 [1;2;3] //desired result [3; 2; 1; 9]
the actual result will be [9; 3; 2; 1]. If the comment is a typo, and that is in fact your desired result, then Luiso's answer works. Otherwise, there is no material difference between addThenReverse and reverseThenAdd, because "add" means something different (appending and prepending) in each case.
Note that I think in both cases, the first case should be
| [] -> [n]
rather than
| [] -> []
In fact, I don't think you need the match statement at all. I think the mathematically correct formulation would be:
let addThenReverse n list = n::list |> List.rev
let reverseThenAdd n list = n::(list |> List.rev)
Then you would have
addThenReverse 0 [] // result: [0]
reverseThenAdd 0 [] // result: [0]
addThenReverse 9 [1; 2; 3] // result: [3; 2; 1; 9]
reverseThenAdd 9 [1; 2; 3] // result: [9; 3; 2; 1]
ADDENDUM
I'm a fan of expressive code. As elegant as F# is, it is still possible to write code that obscures what you're actually trying to do. The code above works, but you can make it more expressive, and learn a bit more about how the language works, by using the composition operator:
let add n list = n::list
let reverse = List.rev
let addThenReverse n = add n >> reverse
let reverseThenAdd n = reverse >> add n
This gives the same results as before, but it expresses what you're doing more clearly. True to the spirit of functional programming, you're telling the compiler what to do, rather than how to do it.
let reverseThenAdd n list = List.rev list # [n]
Related
I have this code:
let rec combinations acc listC =
match listC with
| [] -> acc
| h::t ->
let next = [h]::List.map (fun t -> h::t) acc # acc
combinations next t
It looks tail recursive, but I keep getting stack overflows with it. Any ideas on how to make it work?
combinations is tail recursive. Your problem is with the # operator. Appending a list with it iterates the whole list, so as your acc becomes large, you will get a SO.
You can see here, that the # operator is not tail recursive. The non-optimized version looks like: let rec (#) x y = match x with [] -> y | (h::t) -> h :: (t # y).
To get around this problem, there are a couple of options:
If you don't care about order, you could write a tail-recursive method to prepend the result like this:
let rec prepend lst1 lst2 =
match lst1 with
| [] -> lst2
| head::tail -> prepend tail (head::lst2)
> prepend [1;2;3;4] [5;6;7;8];;
val it : int list = [4; 3; 2; 1; 5; 6; 7; 8]
If you care about order, you could write a method to first reverse the list and then prepend it. The drawback of this, of course, is that it will require twice as much memory since you are allocating an additional list to hold the reversed version of the original list. You can reuse the previous function to write something like this:
let prepend2 lst1 lst2 =
prepend (prepend lst1 []) lst2
> prepend2 [1;2;3;4] [5;6;7;8];;
val it : int list = [1; 2; 3; 4; 5; 6; 7; 8]
I have a list of numbers and want to get the list of distances between the numbers.
For example:
[1; 3; 8; 10; 12] → [2; 5; 2; 2]
Here is my code:
let rec diffs lst acc =
match List.length lst > 1 with
| true ->
let first = List.head lst
let second = List.head (List.tail lst)
diffs (List.tail lst) (List.append acc [second - first])
| false -> acc
I am just wondering if there is any better solution ?
Probably the most straightforward way using what F# gives you out of the box:
let diffs =
Seq.pairwise
>> Seq.map (fun (a,b) -> b - a)
>> List.ofSeq
In general, calls to List.head, tail or append, particularly if they appear in a recursive function, are mild code smells in my book. They usually mean that the function can be written in a different, more streamlined way (case in point - #John's approach in the other answer, which you can easier map to the code you started with).
One more tip - you extend your accumulator using (List.append acc [second - first]), which is very wasteful. You need to traverse and copy the entire list to add elements at the end. The usual pattern is to add the elements from the head ((second - first) :: acc) and reverse the accumulator when you return.
A translation to something more idiomatic
let rec diffs lst =
match lst with
| head::head2::tail -> (head2-head)::(diffs (head2::tail)
| _ -> []
Prepending to a list in F# is somewhat annoying because once you're done you have to reverse it. Is there a way to build a list straight from start?
If you need to append elements to the end, you can use the type known as DList. There is an implementation available in FSharpX.
However, there is some runtime overhead associated with this (e.g. see the comments here) and so I think that building list by prepending and then reversing is generally going to be more efficient. It is also quite standard thing to do in functional programming - it may look a bit confusing at first, but it is a very common "design pattern" when implementing recursive functions that walk over lists, so I would not try to avoid it.
There is nothing wrong with prepending and reversing the list. You can use append (#) on a single-element list, but it is a code smell. A tolerable (tail-recursive) approach is:
let appendSingle xs x =
[ yield! xs
yield x ]
All the above solutions have O(n) execution time.
For your use case, you could keep a private ResizeArray to avoid the use of reverse. It is fine since mutability is hidden. Compare this function
let filter f l =
let rec loop acc l =
match l with
| [] -> List.rev acc
| x::xs when f x -> loop (x::acc) xs
| x::xs -> loop acc xs
loop [] l
with its more efficient counterpart
let filter f l =
let rec loop (acc : ResizeArray<_>) l =
match l with
| [] -> Seq.toList acc
| x::xs when f x ->
acc.Add(x)
loop acc xs
| x::xs -> loop acc xs
loop (ResizeArray()) l
Referring back to your original code, I think what you are looking for is to use List.foldBack rather than List.fold. Essentially, foldBack repeatedly applies the folder function starting from the end of the list rather than from the start of the list. It's not as efficient as fold but it's better to use foldBack and avoid reversing the list.
With foldBack, your accumulation function folder is applied to a list x0::x1::...::xlast as follows, where the initial argument to folder isinit:
folder x0 (folder x1 ( ... (folder xlast init) ... ) )
c.f. fold
folder (... (folder (folder init x0) x1) ...) xlast
There are some other answers to your original question that suggest alternative solutions, but sticking with your code, substituting foldBack for fold results in a first implementation
let chunkOrig items chunkSize =
let folder =
fun x (result, chunk) ->
if List.length chunk < chunkSize then
(result, x::chunk)
else
(chunk::result, [x])
let (a,b) = List.foldBack folder items ([], [])
b::a
Already this is a lot simpler, as all the list reversing has gone. And it seems to work.
> chunkOrig [1..10] 2;;
val it : int list list = [[1; 2]; [3; 4]; [5; 6]; [7; 8]; [9; 10]]
However when your list doesn't divide into equal chunks it goes wrong, because foldBack starts from the last element.
> chunkOrig [1..11] 2;;
val it : int list list = [[1]; [2; 3]; [4; 5]; [6; 7]; [8; 9]; [10; 11]]
What you need to do is parameterise your local function folder by the length remaining in the current chunk rather than by the chunk itself.
let chunk items chunkSize =
let folder =
fun x (result, lenLeft) ->
if lenLeft > 0 then
match result with
| [] -> ([[x]], lenLeft-1)
| r0::rtail -> ((x::r0)::rtail, lenLeft-1)
else
([x]::result, chunkSize-1)
let (result, lenLeft) = List.foldBack folder items ([], (List.length items) % chunkSize)
result
> chunk [1..10] 2;;
val it : int list list = [[1; 2]; [3; 4]; [5; 6]; [7; 8]; [9; 10]]
> chunk [1..11] 2;;
val it : int list list = [[1; 2]; [3; 4]; [5; 6]; [7; 8]; [9; 10]; [11]]
Append x to xs like this:
xs # [x]
Note that this is O(n).
I have a sequence of integers representing dice in F#.
In the game in question, the player has a pool of dice and can choose to play one (governed by certain rules) and keep the rest.
If, for example, a player rolls a 6, 6 and a 4 and decides to play one the sixes, is there a simple way to return a sequence with only one 6 removed?
Seq.filter (fun x -> x != 6) dice
removes all of the sixes, not just one.
Non-trivial operations on sequences are painful to work with, since they don't support pattern matching. I think the simplest solution is as follows:
let filterFirst f s =
seq {
let filtered = ref false
for a in s do
if filtered.Value = false && f a then
filtered := true
else yield a
}
So long as the mutable implementation is hidden from the client, it's still functional style ;)
If you're going to store data I would use ResizeArray instead of a Sequence. It has a wealth of functions built in such as the function you asked about. It's simply called Remove. Note: ResizeArray is an abbreviation for the CLI type List.
let test = seq [1; 2; 6; 6; 1; 0]
let a = new ResizeArray<int>(test)
a.Remove 6 |> ignore
Seq.toList a |> printf "%A"
// output
> [1; 2; 6; 1; 0]
Other data type options could be Array
let removeOneFromArray v a =
let i = Array.findIndex ((=)v) a
Array.append a.[..(i-1)] a.[(i+1)..]
or List
let removeOneFromList v l =
let rec remove acc = function
| x::xs when x = v -> List.rev acc # xs
| x::xs -> remove (x::acc) xs
| [] -> acc
remove [] l
the below code will work for a list (so not any seq but it sounds like the sequence your using could be a List)
let rec removeOne value list =
match list with
| head::tail when head = value -> tail
| head::tail -> head::(removeOne value tail)
| _ -> [] //you might wanna fail here since it didn't find value in
//the list
EDIT: code updated based on correct comment below. Thanks P
EDIT: After reading a different answer I thought that a warning would be in order. Don't use the above code for infite sequences but since I guess your players don't have infite dice that should not be a problem but for but for completeness here's an implementation that would work for (almost) any
finite sequence
let rec removeOne value seq acc =
match seq.Any() with
| true when s.First() = value -> seq.Skip(1)
| true -> seq.First()::(removeOne value seq.Skip(1))
| _ -> List.rev acc //you might wanna fail here since it didn't find value in
//the list
However I recommend using the first solution which Im confident will perform better than the latter even if you have to turn a sequence into a list first (at least for small sequences or large sequences with the soughtfor value in the end)
I don't think there is any function that would allow you to directly represent the idea that you want to remove just the first element matching the specified criteria from the list (e.g. something like Seq.removeOne).
You can implement the function in a relatively readable way using Seq.fold (if the sequence of numbers is finite):
let removeOne f l =
Seq.fold (fun (removed, res) v ->
if removed then true, v::res
elif f v then true, res
else false, v::res) (false, []) l
|> snd |> List.rev
> removeOne (fun x -> x = 6) [ 1; 2; 6; 6; 1 ];
val it : int list = [1; 2; 6; 1]
The fold function keeps some state - in this case of type bool * list<'a>. The Boolean flag represents whether we already removed some element and the list is used to accumulate the result (which has to be reversed at the end of processing).
If you need to do this for (possibly) infinite seq<int>, then you'll need to use GetEnumerator directly and implement the code as a recursive sequence expression. This is a bit uglier and it would look like this:
let removeOne f (s:seq<_>) =
// Get enumerator of the input sequence
let en = s.GetEnumerator()
let rec loop() = seq {
// Move to the next element
if en.MoveNext() then
// Is this the element to skip?
if f en.Current then
// Yes - return all remaining elements without filtering
while en.MoveNext() do
yield en.Current
else
// No - return this element and continue looping
yield en.Current
yield! loop() }
loop()
You can try this:
let rec removeFirstOccurrence item screened items =
items |> function
| h::tail -> if h = item
then screened # tail
else tail |> removeFirstOccurrence item (screened # [h])
| _ -> []
Usage:
let updated = products |> removeFirstOccurrence product []
I've trying to learn F#. I'm a complete beginner, so this might be a walkover for you guys :)
I have the following function:
let removeEven l =
let n = List.length l;
let list_ = [];
let seq_ = seq { for x in 1..n do if x % 2 <> 0 then yield List.nth l (x-1)}
for x in seq_ do
let list_ = list_ # [x];
list_;
It takes a list, and return a new list containing all the numbers, which is placed at an odd index in the original list, so removeEven [x1;x2;x3] = [x1;x3]
However, I get my already favourite error-message: Incomplete construct at or before this point in expression...
If I add a print to the end of the line, instead of list_:
...
print_any list_;
the problem is fixed. But I do not want to print the list, I want to return it!
What causes this? Why can't I return my list?
To answer your question first, the compiler complains because there is a problem inside the for loop. In F#, let serves to declare values (that are immutable and cannot be changed later in the program). It isn't a statement as in C# - let can be only used as part of another expression. For example:
let n = 10
n + n
Actually means that you want the n symbol to refer to the value 10 in the expression n + n. The problem with your code is that you're using let without any expression (probably because you want to use mutable variables):
for x in seq_ do
let list_ = list_ # [x] // This isn't assignment!
list_
The problematic line is an incomplete expression - using let in this way isn't allowed, because it doesn't contain any expression (the list_ value will not be accessed from any code). You can use mutable variable to correct your code:
let mutable list_ = [] // declared as 'mutable'
let seq_ = seq { for x in 1..n do if x % 2 <> 0 then yield List.nth l (x-1)}
for x in seq_ do
list_ <- list_ # [x] // assignment using '<-'
Now, this should work, but it isn't really functional, because you're using imperative mutation. Moreover, appending elements using # is really inefficient thing to do in functional languages. So, if you want to make your code functional, you'll probably need to use different approach. Both of the other answers show a great approach, although I prefer the example by Joel, because indexing into a list (in the solution by Chaos) also isn't very functional (there is no pointer arithmetic, so it will be also slower).
Probably the most classical functional solution would be to use the List.fold function, which aggregates all elements of the list into a single result, walking from the left to the right:
[1;2;3;4;5]
|> List.fold (fun (flag, res) el ->
if flag then (not flag, el::res) else (not flag, res)) (true, [])
|> snd |> List.rev
Here, the state used during the aggregation is a Boolean flag specifying whether to include the next element (during each step, we flip the flag by returning not flag). The second element is the list aggregated so far (we add element by el::res only when the flag is set. After fold returns, we use snd to get the second element of the tuple (the aggregated list) and reverse it using List.rev, because it was collected in the reversed order (this is more efficient than appending to the end using res#[el]).
Edit: If I understand your requirements correctly, here's a version of your function done functional rather than imperative style, that removes elements with odd indexes.
let removeEven list =
list
|> Seq.mapi (fun i x -> (i, x))
|> Seq.filter (fun (i, x) -> i % 2 = 0)
|> Seq.map snd
|> List.ofSeq
> removeEven ['a'; 'b'; 'c'; 'd'];;
val it : char list = ['a'; 'c']
I think this is what you are looking for.
let removeEven list =
let maxIndex = (List.length list) - 1;
seq { for i in 0..2..maxIndex -> list.[i] }
|> Seq.toList
Tests
val removeEven : 'a list -> 'a list
> removeEven [1;2;3;4;5;6];;
val it : int list = [1; 3; 5]
> removeEven [1;2;3;4;5];;
val it : int list = [1; 3; 5]
> removeEven [1;2;3;4];;
val it : int list = [1; 3]
> removeEven [1;2;3];;
val it : int list = [1; 3]
> removeEven [1;2];;
val it : int list = [1]
> removeEven [1];;
val it : int list = [1]
You can try a pattern-matching approach. I haven't used F# in a while and I can't test things right now, but it would be something like this:
let rec curse sofar ls =
match ls with
| even :: odd :: tl -> curse (even :: sofar) tl
| even :: [] -> curse (even :: sofar) []
| [] -> List.rev sofar
curse [] [ 1; 2; 3; 4; 5 ]
This recursively picks off the even elements. I think. I would probably use Joel Mueller's approach though. I don't remember if there is an index-based filter function, but that would probably be the ideal to use, or to make if it doesn't exist in the libraries.
But in general lists aren't really meant as index-type things. That's what arrays are for. If you consider what kind of algorithm would require a list having its even elements removed, maybe it's possible that in the steps prior to this requirement, the elements can be paired up in tuples, like this:
[ (1,2); (3,4) ]
That would make it trivial to get the even-"indexed" elements out:
thelist |> List.map fst // take first element from each tuple
There's a variety of options if the input list isn't guaranteed to have an even number of elements.
Yet another alternative, which (by my reckoning) is slightly slower than Joel's, but it's shorter :)
let removeEven list =
list
|> Seq.mapi (fun i x -> (i, x))
|> Seq.choose (fun (i,x) -> if i % 2 = 0 then Some(x) else None)
|> List.ofSeq