How to set default argument value in F#? - f#

Take this function as an example:
// Sequence of random numbers
open System
let randomSequence m n =
seq {
let rng = Random ()
while true do
yield rng.Next (m, n)
}
randomSequence 8 39
The randomSequence function takes two arguments: m, n. This works fine as a normal function. I would like to set the default for m, n, for example:
(m = 1, n = 100)
When there's no arguments given, the function take the default value. Is it possible in F#?

You can often achieve the same effect as overloading with a Discriminated Union.
Here's a suggestion based on the OP:
type Range = Default | Between of int * int
let randomSequence range =
let m, n =
match range with
| Default -> 1, 100
| Between (min, max) -> min, max
seq {
let rng = new Random()
while true do
yield rng.Next(m, n) }
Notice the introduction of the Range Discriminated Union.
Here are some (FSI) examples of usage:
> randomSequence (Between(8, 39)) |> Seq.take 10 |> Seq.toList;;
val it : int list = [11; 20; 36; 30; 35; 16; 38; 17; 9; 29]
> randomSequence Default |> Seq.take 10 |> Seq.toList;;
val it : int list = [98; 31; 29; 73; 3; 75; 17; 99; 36; 25]
Another option is to change the randomSequence ever so slightly to take a tuple instead of two values:
let randomSequence (m, n) =
seq {
let rng = new Random()
while true do
yield rng.Next(m, n) }
This would allow you to also define a default value, like this:
let DefaultRange = 1, 100
Here are some (FSI) examples of usage:
> randomSequence (8, 39) |> Seq.take 10 |> Seq.toList;;
val it : int list = [30; 37; 12; 32; 12; 33; 9; 23; 31; 32]
> randomSequence DefaultRange |> Seq.take 10 |> Seq.toList;;
val it : int list = [72; 2; 55; 88; 21; 96; 57; 46; 56; 7]

Optional parameters are permitted only on members [...]
https://msdn.microsoft.com/en-us/library/dd233213.aspx
So, for your current example, I think it is impossible.
But you could wrap the functionality:
type Random =
static member sequence(?m, ?n) =
let n = defaultArg n 100
let rng = new System.Random()
match m with
| None -> Seq.initInfinite (fun _ -> rng.Next(1, n))
| Some(m) -> Seq.initInfinite (fun _ -> rng.Next(m, n))
and then use it like this:
let randomSequence = Random.sequence(2, 3)
let randomSequence' = Random.sequence(n = 200)
let randomSequence'' = Random.sequence()
Explanation: optional parameters can either be fully Optional (m) or defaultArgs (n). I like shadowing (reusing the same name) these parameters, but that's debatable.

This seems to be the most elegant solution to this problem:
//define this helper function
let (|Default|) defaultValue input =
defaultArg input defaultValue
//then specify default parameters like this
let compile (Default true optimize) =
optimize
//or as the OP asks
let randomSequence (Default 1 m) (Default 100 n) =
seq {
let rng = new System.Random()
while true do
yield rng.Next(m,n)
}
Credits:
http://fssnip.net/5z

let randomSequence m n=
seq {
let rng = new Random()
while true do
yield rng.Next(m,n)
}
let randomSequenceWithDefaults() =
randomSequence 1 100
So instead, call randomSequenceWithDefaults()

Related

How to get a sublist or a subsequence in F#

I am trying to truncate this sequence like you can do with arrays in F#
let sublist sequ (i:int) (n:int) =
let item = Seq.item(n-i) sequ
let start = Seq.item i sequ
let ending = Seq.item n sequ
Seq.truncate(item) (seq{start..ending})
sublist [|25..92|] 5 10
like it can be done here
Array.sub [|5..20|] 3 10
You forgot to write the expected results.
You can use take and skip as in the linked answer in the comments:
let sublist sequ (i:int) (n:int) =
sequ |> Seq.skip i |> Seq.take (n-1)
Notice that if you are dealing with arrays you can use array slices:
[|25..92|].[5..10]
>
val it : int [] = [|30; 31; 32; 33; 34; 35|]
[|5..20|].[3..10]
>
val it : int [] = [|8; 9; 10; 11; 12; 13; 14; 15|]

f# sequence of running total

Ok, this looks like it should be easy, but I'm just not getting it. If I have a sequence of numbers, how do I generate a new sequence made up of the running totals? eg for a sequence [1;2;3;4], I want to map it to [1;3;6;10]. In a suitably functional way.
Use List.scan:
let runningTotal = List.scan (+) 0 >> List.tail
[1; 2; 3; 4]
|> runningTotal
|> printfn "%A"
Seq.scan-based implementation:
let runningTotal seq' = (Seq.head seq', Seq.skip 1 seq') ||> Seq.scan (+)
{ 1..4 }
|> runningTotal
|> printfn "%A"
Another variation using Seq.scan (Seq.skip 1 gets rid of the leading zero):
> {1..4} |> Seq.scan (+) 0 |> Seq.skip 1;;
val it : seq<int> = seq [1; 3; 6; 10]
> Seq.scan (fun acc n -> acc + n) 0 [1;2;3;4];;
val it : seq<int> = seq [0; 1; 3; 6; ...]
With lists:
> [1;2;3;4] |> List.scan (fun acc n -> acc + n) 0 |> List.tail;;
val it : int list = [1; 3; 6; 10]
Edit: Another way with sequences:
let sum s = seq {
let x = ref 0
for i in s do
x := !x + i
yield !x
}
Yes, there's a mutable variable, but I find it more readable (if you want to get rid of the leading 0).
Figured it was worthwhile to share how to do this with Record Types in case that's also what you came here looking for.
Below is a fictitious example demonstrating the concept using runner laps around a track.
type Split = double
type Lap = { Num : int; Split : Split }
type RunnerLap = { Lap : Lap; TotalTime : double }
let lap1 = { Num = 1; Split = 1.23 }
let lap2 = { Num = 2; Split = 1.13 }
let lap3 = { Num = 3; Split = 1.03 }
let laps = [lap1;lap2;lap3]
let runnerLapsAccumulator =
Seq.scan
(fun rl l -> { rl with Lap = l; TotalTime = rl.TotalTime + l.Split }) // acumulator
{ Lap = { Num = 0; Split = 0.0 }; TotalTime = 0.0 } // initial state
let runnerLaps = laps |> runnerLapsAccumulator
printfn "%A" runnerLaps
Not sure this is the best way but it should do the trick
let input = [1; 2; 3; 4]
let runningTotal =
(input, 0)
|> Seq.unfold (fun (list, total) ->
match list with
| [] ->
None
| h::t ->
let total = total + h
total, (t, total) |> Some)
|> List.ofSeq

F# split sequence into sub lists on every nth element

Say I have a sequence of 100 elements. Every 10th element I want a new list of the previous 10 elements. In this case I will end up with a list of 10 sublists.
Seq.take(10) looks promising, how can I repeatedly call it to return a list of lists?
now there's Seq.chunkBySize available:
[1;2;3;4;5] |> Seq.chunkBySize 2 = seq [[|1; 2|]; [|3; 4|]; [|5|]]
This is not bad:
let splitEach n s =
seq {
let r = ResizeArray<_>()
for x in s do
r.Add(x)
if r.Count = n then
yield r.ToArray()
r.Clear()
if r.Count <> 0 then
yield r.ToArray()
}
let s = splitEach 5 [1..17]
for a in s do
printfn "%A" a
(*
[|1; 2; 3; 4; 5|]
[|6; 7; 8; 9; 10|]
[|11; 12; 13; 14; 15|]
[|16; 17|]
*)
I have an evolution of three solutions. None of them preserves the ordering of the input elements, which is hopefully OK.
My first solution is quite ugly (making use of ref cells):
//[[4; 3; 2; 1; 0]; [9; 8; 7; 6; 5]; [14; 13; 12; 11; 10]; [17; 16; 15]]
let solution1 =
let split s n =
let i = ref 0
let lst = ref []
seq {
for item in s do
if !i = n then
yield !lst
lst := [item]
i := 1
else
lst := item::(!lst)
i := !i+1
yield !lst
} |> Seq.toList
split {0..17} 5
My second solution factors out the use of ref cells in the first solution, but consequently forces the use of direct IEnumerator access (push in one side, pop out the other)!
//[[17; 16; 15]; [14; 13; 12; 11; 10]; [9; 8; 7; 6; 5]; [4; 3; 2; 1; 0]]
let solution2 =
let split (s:seq<_>) n =
let e = s.GetEnumerator()
let rec each lstlst lst i =
if e.MoveNext() |> not then
lst::lstlst
elif i = n then
each (lst::lstlst) [e.Current] 1
else
each lstlst ((e.Current)::lst) (i+1)
each [] [] 0
split {0..17} 5
My third solution is based on the second solution except it "cheats" by taking a list as input instead of a seq, which enables the most elegant solution using pattern matching as Tomas points out is lacking with seq (which is why we were forced to use direct IEnumerator access).
//[[17; 16; 15]; [14; 13; 12; 11; 10]; [9; 8; 7; 6; 5]; [4; 3; 2; 1; 0]]
let solution3 =
let split inputList n =
let rec each inputList lstlst lst i =
match inputList with
| [] -> (lst::lstlst)
| cur::inputList ->
if i = n then
each inputList (lst::lstlst) [cur] 1
else
each inputList lstlst (cur::lst) (i+1)
each inputList [] [] 0
split [0..17] 5
If preserving the ordering of the elements is important, you can use List.rev for this purpose. For example, in solution2, change the last line of the split function to:
each [] [] 0 |> List.rev |> List.map List.rev
Out of the top of my head:
let rec split size list =
if List.length list < size then
[list]
else
(list |> Seq.take size |> Seq.toList) :: (list |> Seq.skip size |> Seq.toList |> split size)
Perhaps this simple pure implementation might be useful:
let splitAt n xs = (Seq.truncate n xs, if Seq.length xs < n then Seq.empty else Seq.skip n xs)
let rec chunk n xs =
if Seq.isEmpty xs then Seq.empty
else
let (ys,zs) = splitAt n xs
Seq.append (Seq.singleton ys) (chunk n zs)
For example:
> chunk 10 [1..100];;
val it : seq<seq<int>> =
seq
[seq [1; 2; 3; 4; ...]; seq [11; 12; 13; 14; ...];
seq [21; 22; 23; 24; ...]; seq [31; 32; 33; 34; ...]; ...]
> chunk 5 [1..12];;
val it : seq<seq<int>> =
seq [seq [1; 2; 3; 4; ...]; seq [6; 7; 8; 9; ...]; seq [11; 12]]
If in doubt, use fold.
let split n = let one, append, empty = Seq.singleton, Seq.append, Seq.empty
Seq.fold (fun (m, cur, acc) x ->
if m = n then (1, one x, append acc (one cur))
else (m+1, append cur (one x), acc))
(0, empty, empty)
>> fun (_, cur, acc) -> append acc (one cur)
This has the advantage of being fully functional, yet touch each element of the input sequence only once(*) (as opposed to the Seq.take + Seq.skip solutions proposed above).
(*) Assuming O(1) Seq.append. I should certainly hope so.
I found this to be easily the fastest:
let windowChunk n xs =
let range = [0 .. Seq.length xs]
Seq.windowed n xs |> Seq.zip range
|> Seq.filter (fun d -> (fst d) % n = 0)
|> Seq.map(fun x -> (snd x))
i.e. window the list, zip with a list of integers, remove all the overlapping elements, and then drop the integer portion of the tuple.
I think that the solution from Brian is probably the most reasonable simple option. A probelm with sequences is that they cannot be easily processed with the usual pattern matching (like functional lists). One option to avoid that would be to use LazyList from F# PowerPack.
Another option is to define a computation builder for working with IEnumerator type. I wrote something like that recently - you can get it here. Then you can write something like:
let splitEach chunkSize (s:seq<_>) =
Enumerator.toSeq (fun () ->
let en = s.GetEnumerator()
let rec loop n acc = iter {
let! item = en
match item with
| Some(item) when n = 1 ->
yield item::acc |> List.rev
yield! loop chunkSize []
| Some(item) ->
yield! loop (n - 1) (item::acc)
| None -> yield acc |> List.rev }
loop chunkSize [] )
This enables using some functional patterns for list processing - most notably, you can write this as a usual recursive function (similar to the one you would write for lists/lazy lists), but it is imperative under the cover (the let! constructo of iter takes the next element and modifies the enumerator).

Check if an element is within a sequence

how to check if an element is contained within a sequence? I expected some Seq.contains, but i could not find it. Thanks
EDIT:
Or, for an easier task, how to make the diff between two sequences? Like, getting all the elements within a list that doesn not belong to another (or that do)?
Little bit simpler:
let contains x = Seq.exists ((=) x)
Seq.exists
let testseq = seq [ 1; 2; 3; 4 ]
let equalsTwo n = (n = 2)
let containsTwo = Seq.exists equalsTwo testseq
Set is your friend here:
let a = set [0;1;2;3]
let b = set [2;3;4;5]
let c = a - b
let d = b - a
let e = Set.intersect a b
let f = a + b
>
val c : Set<int> = seq [0; 1]
val d : Set<int> = seq [4; 5]
val e : Set<int> = seq [2; 3]
val f : Set<int> = seq [0; 1; 2; 3; ...]
Danny
Seq.exists again, but with slightly different syntax -
let testseq = seq [ 1; 2; 3; 4 ]
let testn = 2
testseq |> Seq.exists (fun x -> x = testn)
See MSDN F#: Seq.exists function: https://msdn.microsoft.com/en-us/library/ee353562.aspx
Lots of other good ones there too!
(Another question, another answer.)
This works, but I don't think that it's the most idomatic way to do it - (you'll need to wait until the US wakes up to find out):
let s1 = seq [ 1; 2; 3; 4 ]
let s2 = seq [ 3; 4; 5; 6 ]
seq {
for a in s1 do
if not (Seq.exists (fun n -> n = a) s2) then
yield a
}

F# Add an element to a sequence

a simple question I cannot find an answer to: how to add an element to a sequence? Eg I have a seq and a newElem XElement I'd like to append to it.
Thanks
Seq.append:
> let x = { 1 .. 5 };;
val x : seq<int>
> let y = Seq.append x [9];; // [9] is a single-element list literal
val y : seq<int>
> y |> Seq.toList;;
val it : int list = [1; 2; 3; 4; 5; 9]
You can also use
let newSeq = Seq.append oldSeq (Seq.singleton newElem)
Which is a slight modification of the first answer but appends sequences instead of a list to a sequence.
given the following code
let startSeq = seq {1..100}
let AppendTest = Seq.append startSeq [101] |> List.ofSeq
let AppendTest2 = Seq.append startSeq (Seq.singleton 101) |> List.ofSeq
let AppendTest3 = seq { yield! startSeq; yield 101 } |> List.ofSeq
looped 10000 executions the run times are
Elapsed 00:00:00.0001399
Elapsed 00:00:00.0000942
Elapsed 00:00:00.0000821
Take from that what you will.
There's also an imperative solution...
> let x = seq {1..5}
> let y = seq { yield! x; yield 9 } // Flatten the list,then append your element
> Seq.to_list y;;
val it : int list = [1; 2; 3; 4; 5; 9]
This may be better if the underlying problem is an imperative one, and it is most natural to use a yield statement in a loop.
let mySeq = seq { for i in 1..10 do yield i };;

Resources