Calling a function from within a sequence construct in F# - f#

I am having problems calling a function from within a sequence construct.
Apparently, the function is being called so lazily that the overall code
does not produce the intended result. Here is the code:
mylist
|> fun myseq ->
seq { for b in mylist do yield { b with status = (getStatus b)}}
Here, mylist is a list of records. I intent to build a sequence out of it
with the field status updated from the function getStatus. It simply does
not work, the function does not appear to run for each iteration of the
for loop as expected.
Appreciate any help.

Sequences are lazy. Your function will not run until the sequence is enumerated.
You need to turn the sequence into a concrete collection type like list or array (which will enumerate the sequence and force your function to run):
seq { for b in mylist do yield { b with status = getStatus b } }
|> Seq.toList
or, if you only care about side effects (which is not your case), use Seq.iter.

Related

How to create an Observable from simple values using rx extensions for F#?

Currently, I have a function that receives raw data from the outside, process it, and sends it to a callback:
let Process callback rawData =
let data = rawData //transforming into actual data....
callback data
callback is a function 'T -> unit. In my case specifically, it's the Post function of a MailboxProcessor (being called like Process mailbox.Post rawData)
The process function is called multiple times, and each time I push the processed data into the mailbox queue. So far so good.
Now I want to change this code in a way I can publish this processed data to various consumers, using the rx extensions for FSharp (FSharp.Control.Reactive). This means that callback will be either an Observable, or a function that publishes to subscribers. How do I do this?
I found two options:
Create a class that implements IObservable, and pass that object to the Process function. I'd like to avoid creating classes if possible.
Use the Subject.behavior. This does exactly what I want, except it requires a initial state, which doesnt make sense semantically in this case, and apparently Subjects are frowned upon (from a link in the ReactiveX site http://davesexton.com/blog/post/To-Use-Subject-Or-Not-To-Use-Subject.aspx).
What would be the better way, from a functional programming perspective? Is there a better way?
Here's one idea: You can use an object expression to implement IObservable<_> without the overhead of an explicit class:
let createObservable subscribe =
{
new IObservable<_> with
member __.Subscribe(observer) =
subscribe observer
}
To use this, specify a subscribe function of type IObserver<_> -> IDisposable. No classes needed.
Using the observe { .. } computation builder works, but there is a function in the FSharp.Control.Reactive library that does the same thing:
open FSharp.Control.Reactive
let obs = Observable.ofSeq [1;2;3;4;5]
If I was using the observe { .. } computation builder, I'd also use the fact that it supports for loop, which makes your code a bit simpler:
let Process initialData = observe {
for x in initialData do yield x }
Got it. Fsharp reactive provides the keyword observe from the module FSharp.Control.Reactive.Builders. This allows you to create ad-hoc observables:
open FSharp.Control.Reactive.Builders
//In my real case, "initialData" is a byte stream and
//at each step I read a few bytes off of it
let Process initialData =
let rec loop data =
observe {
match data with
| x :: xs ->
yield x
yield! loop xs
| [] -> ()
}
loop initialData
let obs = Process ([1;2;3;4;5])
obs.Subscribe(fun d -> printfn "Consumer A: %A" d) |> ignore
obs.Subscribe(fun d -> printfn "Consumer B: %A" d) |> ignore
Threading.Thread.Sleep 1000
obs.Subscribe(fun d -> printfn "Late consumer: %A" d) |> ignore
Important to note that this creates a cold observable, so the Late consumer receives all events.

Why data parameter comes last

Why have the data parameter in F# to come last, like the following code snippet shows:
let startsWith lookFor (s:string) = s.StartsWith(lookFor)
let str1 =
"hello"
|> startsWith "h"
I think part of your answer is in your question. The |> (forward pipe) operator lets you specify the last parameter to a function before you call it. If the parameters were in the opposite order, then that wouldn't work. The best examples of the power of this are with chaining of functions that operate on lists. Each function takes a list as its last parameter and returns a list that can be passed to the next function.
From http://www.tryfsharp.org/Learn/getting-started#chaining-functions:
[0..100]
|> List.filter (fun x -> x % 2 = 0)
|> List.map (fun x -> x * 2)
|> List.sum
The |> operator allows you to reorder your code by specifying the last
argument of a function before you call it. This example is
functionally equivalent to the previous code, but it reads much more
cleanly. First, it creates a list of numbers. Then, it pipes that list
of numbers to filter out the odds. Next, it pipes that result to
List.map to double it. Finally, it pipes the doubled numbers to
List.sum to add them together. The Forward Pipe Operator reorganizes
the function chain so that your code reads the way you think about the
problem instead of forcing you to think inside out.
As mentioned in the comments there is also the concept of currying, but I don't think that is as easy to grasp as chaining functions.

f# signature matching explained

I am running into difficulty with F# in numerous scenarios. I believe I'm not grasping some fundamental concepts. I'm hoping someone can track my reasoning and figure out the (probably many) things I'm missing.
Say I'm using Xunit. What I'd like to do is, provided two lists, apply the Assert.Equal method pairwise. For instance:
Open Xunit
let test1 = [1;2;3]
let test2 = [1;2;4]
List.map2 Assert.Equal test1 test2
The compiler complains that the function Equal does not take one parameter. As far as I can tell, shouldn't map2 be providing it 2 parameters?
As a sanity check, I use the following code in f# immediate:
let doequal = fun x y -> printf "result: %b\n" (x = y)
let test1 = [1;2;3]
let test2 = [1;2;4]
List.map2 doequal test1 test2;;
This seems identical. doequal is a lambda taking two generic parameters and returning unit. List.map2 hands each argument pairwise into the lambda and I get exactly what I expected as output:
result: true
result: true
result: false
So what gives? Source shows Xunit.Equal has signature public static void Equal<T>(T expected, T actual). Why won't my parameters map right over the method signature?
EDIT ONE
I thought two variables x and y vs a tuple (x, y) could construct and deconstruct interchangeably. So I tried two options and got different results. It seems the second may be further along than the first.
List.map2 Assert.Equal(test1, test2)
The compiler now complains that 'Successive arguments should be separated spaces or tupled'
List.map2(Assert.Equal(test1, test2))
The compiler now complains that 'A unique overload method could not be determined... A type annotation may be needed'
I think that part of the problem comes from mixing methods (OO style) and functions (FP style).
FP style functions have multiple parameters separated by spaces.
OO style methods have parens and parameters separated by commas.
Methods in other .NET libraries are always called using "tuple" syntax (actually subtly different from tuples though) and a tuple is considered to be one parameter.
The F# compiler tries to handle both approaches, but needs some help occasionally.
One approach is to "wrap" the OO method with an FP function.
// wrap method call with function
let assertEqual x y = Assert.Equal(x,y)
// all FP-style functions
List.map2 assertEqual test1 test2
If you don't create a helper function, you will often need to convert multiple function parameters to one tuple when calling a method "inline" with a lambda:
List.map2 (fun x y -> Assert.Equal(x,y)) test1 test2
When you mix methods and functions in one line, you often get the "Successive arguments should be separated" error.
printfn "%s" "hello".ToUpper()
// Error: Successive arguments should be separated
// by spaces or tupled
That's telling you that the compiler is having problems and needs some help!
You can solve this with extra parens around the method call:
printfn "%s" ("hello".ToUpper()) // ok
Or sometimes, with a reverse pipe:
printfn "%s" <| "hello".ToUpper() // ok
The wrapping approach is often worth doing anyway so that you can swap the parameters to make it more suitable for partial application:
// wrap method call with function AND swap params
let contains searchFor (s:string) = s.Contains(searchFor)
// all FP-style functions
["a"; "b"; "c"]
|> List.filter (contains "a")
Note that in the last line I had to use parens to give precedence to contains "a" over List.filter
public static void Equal<T>(T expected, T actual)
doesn't take two parameters - it takes one parameter, which is a tuple with two elements: (T expected, T actual).
Try this instead:
List.map2 Assert.Equal(test1, test2)
It's all there in the type signatures.
The signature for Assert.Equals is something along the lines of 'a * 'a -> unit. List.map2 expects a 'a -> 'b -> 'c.
They just don't fit together.
List.map2 (fun x y -> Assert.Equal(x,y)) test1 test2 - works because the lambda wrapping Equals has the expected signature.
List.zip test1 test2 |> List.map Assert.Equal - works because you now have a single list of tuples, and since List.map wants an 'a -> 'b function (where 'a is now a tuple), Assert.Equal is now fair game.
It's simply not true that two values and a tuple are implicitly interchangeable. At least not as far as F# the language is concerned, or the underlying IL representation is concerned. You can think that it's that way when you call into F# code from, say, C# - an 'a -> 'b -> 'c function there is indeed called the same way syntactically as an 'a * 'b -> 'c function - but this is more of an exception than a rule.
According to its signature Xunit.Assert.Equal() takes a single 2 values tuple parameter

Comparing values in loop inside function

I want to make a function that takes an integer list as argument and compares every value and returns the largest value. In C# I would simply iterate through every value in the list, save the largest to a variable and return it, I'm hoping F# works similarly but the syntax is kinda iffy for me, here's what my code looks like. Also max2 is a function that compares 2 values and returns the largest.
let max_list list =
let a = 0 : int
match list with
| head :: tail -> (for i in list do a = max2 i a) a
| [] -> failwith "sry";;
You could use mutable variable and write the code using for loop, just like in C#. However, if you're doing this to learn F# and functional concepts, then it's good idea to use recursion.
In this case, recursive function is a bit longer, but it demonstrates the key concepts including pattern matching - so learning the tricks is something that will be useful when writing more complicated F# code.
The key idea is to write a function that takes the largest value found so far and calls itself recursively until it reaches the end of the list.
let max_list list =
// Inner recursive function that takes the largest value found so far
// and a list to be processed (if it is empty, it returns 'maxSoFar')
let rec loop maxSoFar list =
match list with
// If the head value is greater than what we found so far, use it as new greater
| head::tail when head > maxSoFar -> loop head tail
// If the head is smaller, use the previous maxSoFar value
| _::tail -> loop maxSoFar tail
// At the end, just return the largest value found so far
| [] -> maxSoFar
// Start with head as the greatest and tail as the rest to be processed
// (fails for empty list - but you could match here to give better error)
loop (List.head list) (List.tail list)
As a final note, this will be slow because it uses generic comparison (via an interface). You can make the function faster using let inline max_list list = (...). That way, the code will use native comparison instruction when used with primitive types like int (this is really a special case - the problem only really happens with generic comparison)
Also know that you can write a nice one-liner using reduce:
let max_list list = List.reduce (fun max x -> if x > max then x else max)
If your intention is to be able to find the maximum value of items in a list where the value of the items is found by the function max2 then this approach works:
let findMax list =
list
|> List.map (fun i -> i, max2 i)
|> List.maxBy snd
|> fst

seq<obj> versus seq<float> in F#

I have the following method:
member this.addColumnWithHeading heading column =
this.addColumn (seq { yield heading; yield! (column |> Seq.map string)})
which takes a string heading and any sequence (which is compiled to seq in this case), creates a sequence of strings and calls another method with this data. However, it doesn't work with column being a sequence of floats:
Error 1 The type 'obj' does not match the type 'float' C:\Users\ga1009\Documents\PhD\cpp\pmi\fsharp\pmi\Program.fs 138
How can I define the method addColumnWithHeading so that it works with floats as well?
The built-in string function is an inline function which uses a statically-resolved generic parameter; since your addColumnWithHeading method is not declared inline, the F# type inference has to assume the values in the sequence are of type obj.
There's a simple solution though -- swap out the string function in favor of "manually" calling .ToString() on the values in the sequence. If you do that, F# will be able to use a standard generic parameter type for the sequence so you can pass a sequence of any type you desire.
member this.addColumnWithHeading heading column =
seq {
yield heading
yield! Seq.map (fun x -> x.ToString()) column }
|> this.addColumn
string is inlined so its argument type has to be resolved at compile-time. Since your member is not inlined it picks the most general type it can (obj in this case). Inlining your method will allow column to remain generic.
member inline x.AddColumnWithHeading(heading, column) =
x.AddColumn(seq { yield heading; yield! Seq.map string column })
EDIT
Per the comments to Jack's answer, you might not need to inline your use of string. Certainly, if column will always be seq<float> you should just add a type annotation. Passing seq<string> and moving the string conversion outside the function is another option.

Resources