Hullo all.
I am a C# programmer, exploring F# in my free time. I have written the following little program for image convolution in 2D.
open System
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye))
|> List.mapi (fun i l -> [for q in 1..i -> 0] # l # [for q in 1..(l.Length - i - 1) -> 0])
|> List.reduce (fun r c -> List.zip r c |> List.map (fun (a, b) -> a + b))
let y = [2; 3; 1; 4]
let x = [4; 1; 2; 3]
printfn "%A" (convolve y x)
My question is: Is the above code an idiomatic F#? Can it be made more concise? (e.g. Is there some shorter way to generate a filled list of 0's (I have used list comprehension in my code for this purpose)). Any changes that can improve its performance?
Any help would be greatly appreciated. Thanks.
EDIT:
Thanks Brian. I didn't get your first suggestion. Here's how my code looks after applying your second suggestion. (I also abstracted out the list-fill operation.)
open System
let listFill howMany withWhat = [for i in 1..howMany -> withWhat]
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye))
|> List.mapi (fun i l -> (listFill i 0) # l # (listFill (l.Length - i - 1) 0))
|> List.reduce (List.map2 (+))
let y = [2; 3; 1; 4]
let x = [4; 1; 2; 3]
printfn "%A" (convolve y x)
Anything else can be improved? Awaiting more suggestions...
As Brian mentioned, the use of # is generally problematic, because the operator cannot be efficiently implemented for (simple) functional lists - it needs to copy the entire first list.
I think Brians suggestion was to write a sequence generator that would generate the list at once, but that's a bit more complicated. You'd have to convert the list to array and then write something like:
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye) |> Array.ofList)
|> List.mapi (fun i l -> Array.init (2 * l.Length - 1) (fun n ->
if n < i || n - i >= l.Length then 0 else l.[n - i]))
|> List.reduce (Array.map2 (+))
In general, if performance is an important concern, then you'll probably need to use arrays anyway (because this kind of problem can be best solved by accessing elements by index). Using arrays is a bit more difficult (you need to get the indexing right), but perfectly fine approach in F#.
Anyway, if you want to write this using lists, then here ara some options. You could use sequence expressions everywhere, which would look like this:
let convolve y (x:_ list) =
[ for i, v1 in x |> List.zip [ 0 .. x.Length - 1] ->
[ yield! listFill i 0
for v2 in y do yield v1 * v2
yield! listFill (x.Length - i - 1) 0 ] ]
|> List.reduce (List.map2 (+))
... or you can also combine the two options and use a nested sequence expression (with yield! to generate zeros and lists) in the lambda function that you're passing to List.mapi:
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye))
|> List.mapi (fun i l ->
[ for _ in 1 .. i do yield 0
yield! l
for _ in 1 .. (l.Length - i - 1) do yield 0 ])
|> List.reduce (List.map2 (+))
The idiomatic solution would be to use arrays and loops just as you would in C. However, you may be interested in the following alternative solution that uses pattern matching instead:
let dot xs ys =
Seq.map2 (*) xs ys
|> Seq.sum
let convolve xs ys =
let rec loop vs xs ys zs =
match xs, ys with
| x::xs, ys -> loop (dot ys (x::zs) :: vs) xs ys (x::zs)
| [], _::(_::_ as ys) -> loop (dot ys zs :: vs) [] ys zs
| _ -> List.rev vs
loop [] xs ys []
convolve [2; 3; 1; 4] [4; 1; 2; 3]
Regarding the zeroes, how about e.g.
[for q in 0..l.Length-1 -> if q=i then l else 0]
(I haven't tested to verify that is exactly right, but hopefully the idea is clear.) In general, any use of # is a code smell.
Regarding overall performance, for small lists this is probably fine; for larger ones, you might consider using Seq rather than List for some of the intermediate computations, to avoid allocating as many temporary lists along the way.
It looks like maybe the final zip-then-map could be replaced by just a call to map2, something like
... fun r c -> (r,c) ||> List.map2 (+)
or possibly even just
... List.map2 (+)
but I'm away from a compiler so haven't double-checked it.
(fun ye -> x |> List.map ((*) ye))
Really ?
I'll admit |> is pretty, but you could just wrote :
(fun ye -> List.map ((*) ye) x)
Another thing that you could do is fuse the first two maps. l |> List.map f |> List.mapi g = l |> List.mapi (fun i x -> g i (f x)), so incorporating Tomas and Brian's suggestions, you can get something like:
let convolve y x =
let N = List.length x
y
|> List.mapi (fun i ye ->
[for _ in 1..i -> 0
yield! List.map ((*) ye) x
for _ in 1..(N-i-1) -> 0])
|> List.reduce (List.map2 (+))
Related
with an array like this:
let a = [| 1.; 2.; nan; 4.; 5. |]
I know that the last value is not a NaN (the list comes from an operation that generates leading NaNs) I want to scan the list from the end and if the value is a nan, replace it with the previous value.
In the case, the output would be:
[| 1.; 2.; 4.; 4.; 5. |]
first, I made this monstrocity:
Array.append a [|a.[^0]|] |> Array.pairwise |> Array.rev |> Array.map (fun (a, b) -> if Double.IsNaN(a) then b else a) |> Array.rev
then a cleaner loop:
seq {
for i = a.Length - 1 downto 0 do
yield if Double.IsNaN(a.[i]) then a.[i+1] else a.[i]
} |> Seq.rev |> Seq.toArray
I was thinking that maybe foldBack would work:
Array.foldBack (fun x acc -> Array.append acc (seq {yield if Double.IsNaN(x) then acc.[^0] else x} |> Seq.toArray)) a Array.empty
but this is ugly as well..
I can't help to think that there has to be a simple elegant way to do this... anyone has an idea?
First of all, you can make your foldBack solution a lot cleaner by realizing that seq { yield foo } |> Seq.toArray is the same as just [|foo|]:
Array.foldBack (fun x acc -> Array.append acc [|if Double.IsNaN(x) then acc.[^0] else x|]) a Array.empty
But a better approach is scan. It's a nice little function that's kind of like map, but each iteration also has access to the result of the previous one. Except, of course, since you're going back-to-front, you'll have to use scanBack:
Array.scanBack (fun x prev -> if Double.IsNaN x then prev else x) a nan
The only problem is that the "seed" of the scan (which is the last parameter - in my example nan) will remain in the resulting array, becoming its last element. So you'd have to filter it out afterwards, but I didn't think it would be a problem since you seemed to be ok reallocating multiple arrays in your foldBack approach:
Array.scanBack (fun x prev -> if Double.IsNaN x then prev else x) a nan
|> Array.takeWhile (not << Double.IsNaN)
Alternatively, you can remember that arrays are mutable, and simply mutate your original array:
for i in 0..(Array.length a - 1) do
if Double.IsNaN a.[i] then a.[i] <- a.[i+1]
You can do this with a single Array.mapi. This is like Array.map but it provides the index of each item.
let fillNans xs =
xs
|> Array.mapi (fun i x -> if Double.IsNaN x then xs.[i+1] else x)
I am currently learning functional programming and F#, and I want to do a loop control until n-2. For example:
Given a list of doubles, find the pairwise average,
e.g. pairwiseAverage [1.0; 2.0; 3.0; 4.0; 5.0] will give [1.5; 2.5; 3.5; 4.5]
After doing some experimenting and searching, I have a few ways to do it:
Method 1:
let pairwiseAverage (data: List<double>) =
[for j in 0 .. data.Length-2 do
yield (data.[j]+data.[j+1])/2.0]
Method 2:
let pairwiseAverage (data: List<double>) =
let averageWithNone acc next =
match acc with
| (_,None) -> ([],Some(next))
| (result,Some prev) -> ((prev+next)/2.0)::result,Some(next))
let resultTuple = List.fold averageWithNone ([],None) data
match resultTuple with
| (x,_) -> List.rev x
Method 3:
let pairwiseAverage (data: List<double>) =
// Get elements from 1 .. n-1
let after = List.tail data
// Get elements from 0 .. n-2
let before =
data |> List.rev
|> List.tail
|> List.rev
List.map2 (fun x y -> (x+y)/2.0) before after
I just like to know if there are other ways to approach this problem. Thank you.
Using only built-ins:
list |> Seq.windowed 2 |> Seq.map Array.average
Seq.windowed n gives you sliding windows of n elements each.
One simple other way is to use Seq.pairwise
something like
list |> Seq.pairwise |> Seq.map (fun (a,b) -> (a+b)/2.0)
The approaches suggested above are appropriate for short windows, like the one in the question. For windows with a length greater than 2 one cannot use pairwise. The answer by hlo generalizes to wider windows and is a clean and fast approach if window length is not too large. For very wide windows the code below runs faster, as it only adds one number and subtracts another one from the value obtained for the previous window. Notice that Seq.map2 (and Seq.map) automatically deal with sequences of different lengths.
let movingAverage (n: int) (xs: float List) =
let init = xs |> (Seq.take n) |> Seq.sum
let additions = Seq.map2 (fun x y -> x - y) (Seq.skip n xs) xs
Seq.fold (fun m x -> ((List.head m) + x)::m) [init] additions
|> List.rev
|> List.map (fun (x: float) -> x/(float n))
xs = [1.0..1000000.0]
movingAverage 1000 xs
// Real: 00:00:00.265, CPU: 00:00:00.265, GC gen0: 10, gen1: 10, gen2: 0
For comparison, the function above performs the calculation above about 60 times faster than the windowed equivalent:
let windowedAverage (n: int) (xs: float List) =
xs
|> Seq.windowed n
|> Seq.map Array.average
|> Seq.toList
windowedAverage 1000 xs
// Real: 00:00:15.634, CPU: 00:00:15.500, GC gen0: 74, gen1: 74, gen2: 71
I tried to eliminate List.rev using foldBack but did not succeed.
A point-free approach:
let pairwiseAverage = List.pairwise >> List.map ((<||) (+) >> (*) 0.5)
Online Demo
Usually not a better way, but another way regardless... ;-]
I have a list like [1..12] and I would like to get a piece like [4..9]. No clue how I can do that, I'm new with F#. I don't know if there is a built-in method for that, but I would like to know the manual way.
[1..12] |> List.filter (fun x -> x >= 4 && x <= 9)
or
[1..12] |> Seq.skip 3 |> Seq.take 6 |> Seq.toList
Lists don't support slicing, but if you use an array instead you can also do this:
[|1..12|].[3..8]
(note 3..8 instead of 4..9 because of 0-based indexing)
To give an immediate answer to your question: how do you take a piece of a list? Pattern matching.
You can use pattern matching to write a function that extracts a range from a list. The basic algorithm is skip each element of the list while E < Min, then take each element while E <= Max. Something like this:
let range min max xs =
let rec skipWhile f = function
| x::xs when f x -> skipWhile f xs
| xs -> xs
let rec takeWhile f acc = function
| x::xs when f x -> takeWhile f (x::acc) xs
| _ -> List.rev acc
xs
|> skipWhile ((>) min)
|> takeWhile ((>=) max) []
[1..12] |> range 4 9
> val it : int list = [4; 5; 6; 7; 8; 9]
Assuming you use the Ocaml-like subset of F# you probably want to use the List standard module, probably its filter function.
Otherwise, a tail recursive function with matching could do.
I am trying to write a list comprehension in F# and can't get it to compile:
[for x in xs do
let y = f(x)
when g(y) -> y]
Is there any way to save an intermediate computation in the middle of a list comprehension? How can I rework this list comprehension so that it compiles?
I would just skip the list comprehension.
let ys = xs |> List.map f |> List.filter g
However it is simple enough to get your code working.
let ys = [ for x in xs do
let y = f(x)
if g(y) then yield y ]
To expand on #ChaosPandion's solution, you could also write this using List.choose -- think of it as a combination of List.map and List.filter which avoids creating an extra list (i.e., instead of creating a list with List.map just to pass it to List.filter).
let ys =
xs
|> List.choose (fun x ->
let y = f x
if g y then Some y else None)
I been recently playing with F# . I was wondering instead of using a for loop to generate a sequence to element which are multiplied with every other element in the list how can I use a Seq map function or something similar to generate something like below.
So for e.g. I have a list [1..10] I would like to apply a fun which generates a result something like
[(1*1); (1*2);(1*3); (1*4); (1*5)......(2*1);(2*2);(2*3).....(3*1);(3*2)...]
How can i achieve this ?.
Many thanks for all you help.
let list = [1..10]
list |> List.map (fun v1 -> List.map (fun v2 -> (v1*v2)) list) |> List.collect id
The List.collect at the end flattens the list of lists.
It works the same with Seq instead of List, if you want a lazy sequence.
Or, using collect as the main iterator, as cfern suggested and obsessivley eliminating anonymous functions:
let flip f x y = f y x
let list = [1..10]
list |> List.collect ((*) >> ((flip List.map) list))
A list comprehension would be the easiest way to do this:
let allpairs L =
[for x in L do
for y in L -> (x*y)]
Or, without using any loops:
let pairs2 L = L |> List.collect (fun x -> L |> List.map (fun y -> (x*y)))
Edit in response to comment:
You could add a self-crossing extension method to a list like this:
type Microsoft.FSharp.Collections.List<'a> with
member L.cross f =
[for x in L do
for y in L -> f x y]
Example:
> [1;2;3].cross (fun x y -> (x,y));;
val it : (int * int) list =
[(1, 1); (1, 2); (1, 3); (2, 1); (2, 2); (2, 3); (3, 1); (3, 2); (3, 3)]
I wouldn't use an extension method in F# myself, is feels a bit C#'ish. But that's mostly because I don't feel that a fluent syntax is needed in F# because I usually chain my functions together with pipe (|>) operators.
My approach would be to extend the List module with a cross function, not the type itself:
module List =
let cross f L1 L2 =
[for x in L1 do
for y in L2 -> f x y]
If you do this, you can use the cross method like any other method of List:
> List.cross (fun x y -> (x,y)) [1;2;3] [1;2;3];;
val it : (int * int) list =
[(1, 1); (1, 2); (1, 3); (2, 1); (2, 2); (2, 3); (3, 1); (3, 2); (3, 3)]
> List.cross (*) [1;2;3] [1;2;3];;
val it : int list = [1; 2; 3; 2; 4; 6; 3; 6; 9]
Or we can implement a general cross product function:
let cross l1 l2 =
seq { for el1 in l1 do
for el2 in l2 do
yield el1, el2 };;
and use this function to get the job done:
cross [1..10] [1..10] |> Seq.map (fun (a,b) -> a*b) |> Seq.toList
To implement the same thing without for loops, you can use the solution using higher-order functions posted by Mau, or you can write the same thing explicitly using recursion:
let cross xs ys =
let rec crossAux ol2 l1 l2 =
match l1, l2 with
// All elements from the second list were processed
| x::xs, [] -> crossAux ol2 xs ol2
// Report first elements and continue looping after
// removing first element from the second list
| x::xs, y::ys -> (x, y)::(crossAux ol2 l1 ys)
// First list is empty - we're done
| [], _ -> []
crossAux ys xs ys
This may be useful if you're learning functional programming and recursion, however, the solution using sequence expressions is far more practically useful.
As a side-note, the first version by Mau can be made a bit nicer, because you can join the call to List.map with a call to List.collect id like this (you can pass the nested processing lambda directly as a parameter to collect). The cross function would look like this (Of course, you can modifiy this to take a parameter to apply to the two numbers instead of creating a tuple):
let cross xs ys =
xs |> List.collect (fun v1 ->
ys |> List.map (fun v2 -> (v1, v2)))
Incidentally, there is a free chapter from my book avaialable, which discusses how sequence expressions and List.collect functions work. It is worth noting, that for in sequence expressions directly corresponds to List.collect, so you can write the code just by using this higher order function:
let cross xs ys =
xs |> List.collect (fun v1 ->
ys |> List.collect (fun v2 -> [(v1, v2)] ))
However, see the free chapter for more information :-).