Is there any advantage to using the .NET lazy operator instead of a plain function?
For example:
let x = lazy ...
let y = lazy (1 + x.Value)
let x = (fun () -> ...)
let y = (fun () -> 1 + x())
The difference between a lazy value and a function is that a lazy value is evaluated only once. It then caches the result and accessing it again will not recalculate the value. A function is evaluated each time you call it.
This has performance implications and it also matters when you have side effects. For example, the following prints "calculating x" just once:
let x = lazy (printfn "calculating x"; 1)
let y = lazy (1 + x.Value)
y.Value + y.Value
The following prints "calculating x" two times:
let x = (fun () -> printfn "calculating x"; 1)
let y = (fun () -> 1 + x())
y () + y ()
Related
I am not coming right with FsCheck, when I try and use Prop.forAll.
I have created two tests to demonstrate what I am doing, expecting them both to fail.
type Data = { value: int }
type NeverAOne =
static member Data () =
Arb.generate<int>
|> Gen.filter (fun x -> x <> 1)
|> Gen.map (fun x -> { value = x })
|> Arb.fromGen
[<Property(Arbitrary = [| typeof<NeverAOne> |] )>] (* Fails *)
let ``Test One`` (x: Data) =
x.value = 1
[<Fact>]
let ``Test Two`` () = (* Passes *)
Prop.forAll (NeverAOne.Data ()) (fun x -> x.value = 1)
In this sample, Test Two passes. If I add breakpoints, I can see it is because no data is generated, so it iterates through 0 samples, which means none fail.
I am convinced that I am using Prop.forAll wrong, but though everything I have read through, I cannot find it.
If you mark the test as a plain Xunit Fact (rather than as a FsCheck Property), you have to explicitly check the property:
[<Fact>]
let ``Test Two`` () =
let prop = Prop.forAll (NeverAOne.Data ()) (fun x -> x.value = 1)
Check.QuickThrowOnFailure prop
The result I get is then:
System.Exception : Falsifiable, after 1 test (0 shrinks) (StdGen (74764374, 296947750)):
Original:
{ value = -2 }
Or you can just mark the test as a Property, of course:
[<Property>]
let ``Test Three`` () =
Prop.forAll (NeverAOne.Data ()) (fun x -> x.value = 1)
Is it possible to debug F# or, like LINQ in C#, is this effectively impossible?
I'm working through Machine Learning Projects for .NET Developers and am using F# for the first time.
I tried to edit the example exercise. The C# version was easy to get running, but my attempt at the F# version just hangs.
What can I do to trace the problem?
open System.IO
type Observation = { Label:string; Pixels: int[] }
type Distance = int[] * int[] -> int
type Classifier = int[] -> string
let toObservation (csvData:string) =
let columns = csvData.Split(',')
let label = columns.[0]
let pixels = columns.[1..] |> Array.map int
{ Label = label; Pixels = pixels }
let reader path =
let data = File.ReadAllLines path
data.[1..]
|> Array.map toObservation
let trainingPath = __SOURCE_DIRECTORY__ + #"../../Data/trainingsample.csv"
let training = reader trainingPath
let manhattanDistance (pixels1,pixels2) =
Array.zip pixels1 pixels2
|> Array.map (fun (x,y) -> abs (x-y))
|> Array.sum
let euclideanDistance (pixels1,pixels2) =
Array.zip pixels1 pixels2
|> Array.map (fun (x,y) -> pown (x-y) 2)
|> Array.sum
let dotCountDistance(pixels1, pixels2) =
let t1 = pixels1 |> Array.map (fun(z) -> if z > 128 then 1 else 0) |> Array.sum
let t2 = pixels2 |> Array.map (fun(z) -> if z > 128 then 1 else 0) |> Array.sum
abs(t1 - t2)
let train (trainingset:Observation[]) (dist:Distance) =
let classify (pixels:int[]) =
trainingset
|> Array.minBy (fun x -> dist (x.Pixels, pixels))
|> fun x -> x.Label
classify
//
// This is my new function
//
let train2 (trainingset:Observation[]) (dist:Distance) =
let classify (pixels:int[]) =
trainingset
|> Array.map (fun(z) -> dist(z.Pixels, pixels), z.Label)
|> Array.groupBy(fun (a, y) -> y)
|> Array.map(fun (lbl, ds) -> lbl, (ds |> Array.map(fun (p, q) -> p) |> Array.sum ) * 100 / (ds |> Array.length))
|> Array.sortByDescending( fun (lbl, s) -> s)
|> fun z -> z.[0]
|> fun (lbl, s) -> lbl
classify
//
//
//
let validationPath = __SOURCE_DIRECTORY__ + #"../../Data/validationsample.csv"
let validation = reader validationPath
let evaluate validationSet classifier =
validationSet
|> Array.averageBy (fun x -> if classifier x.Pixels = x.Label then 1. else 0.)
|> printfn "Correct: %.3f"
let manhattanModel = train training manhattanDistance
let euclideanModel = train training euclideanDistance
let dotCountModel = train training dotCountDistance
let manhattanModel2 = train2 training manhattanDistance
let euclideanModel2 = train2 training euclideanDistance
let dotCountModel2 = train2 training dotCountDistance
printfn "Manhattan"
evaluate validation manhattanModel // <------------------- This just hangs.
printfn "Euclidean"
evaluate validation euclideanModel
printfn "Dot Count"
evaluate validation dotCountModel
// Illustration: full distance function
let d (X,Y) =
Array.zip X Y
|> Array.map (fun (x,y) -> pown (x-y) 2)
|> Array.sum
|> sqrt
Here is ,y C# version that works
return data.Select(z => new { z.Label, D = distance.Between(z.Pixels, pixels) })
.GroupBy(z => z.Label)
.Select(z => new { Label = z.Key, MeanDistance = z.Average(y => y.D) })
.OrderBy(z => z.MeanDistance).First()
.Label;
You can debug a script in F# Interactive (make sure you have this option turned on, first).
I had the same behavior you did, it hangs. I ran the same code as a console program, and it ran in a few seconds. (The output was "Correct: 0.934"). So, I believe this is a problem, perhaps a bug, with F# Interactive.
I'm trying to build F# equivalent code for the Python code appearing here, I've the below code:
let tripleExponentialSmoothing series slen alpha beta gamma nPreds =
let result : float list = []
let mutable smooth = 0.
let mutable trend = 0.
let seasonals = initialSeasonalComponents series 12
for i in 0..(series.Length+nPreds-1) do
match i with
| 0 -> // initial values
smooth <- series |> Array.head |> float
trend <- initialTrend series slen
result |> List.append [series |> Array.head |> float] |> ignore
| i when i >= series.Length -> // we are forecasting
let m = i - series.Length + 1
result |> List.append [(smooth + float m * trend) + seasonals.Item(i%slen)] |> ignore
| _ ->
let v = series |> Array.head |> float
let lastSmooth = smooth
smooth <- alpha*(v-seasonals.Item(i%slen)) + (1.-alpha)*(smooth+trend)
trend <- beta * (smooth-lastSmooth) + (1.-beta)*trend
seasonals.Item(i%slen) <- gamma*(v-smooth) + (1.-gamma)*seasonals.Item(i%slen)
result |> List.append [smooth + trend + seasonals.Item(i%slen)] |> ignore
result
For which I got the below error:
warning FS0020: The result of this expression is implicitly ignored.
Consider using 'ignore' to discard this value explicitly, e.g. 'expr
|> ignore', or 'let' to bind the result to a name, e.g. 'let result =
expr'.
I tried to write the above as conversion of the below Python code:
def triple_exponential_smoothing(series, slen, alpha, beta, gamma, n_preds):
result = []
seasonals = initial_seasonal_components(series, slen)
for i in range(len(series)+n_preds):
if i == 0: # initial values
smooth = series[0]
trend = initial_trend(series, slen)
result.append(series[0])
continue
if i >= len(series): # we are forecasting
m = i - len(series) + 1
result.append((smooth + m*trend) + seasonals[i%slen])
else:
val = series[i]
last_smooth, smooth = smooth, alpha*(val-seasonals[i%slen]) + (1-alpha)*(smooth+trend)
trend = beta * (smooth-last_smooth) + (1-beta)*trend
seasonals[i%slen] = gamma*(val-smooth) + (1-gamma)*seasonals[i%slen]
result.append(smooth+trend+seasonals[i%slen])
return result
What the wrong things I did, and what is the correct code equivalent to the mentioned Python's one.
You are running the for as a side effect.
Maybe you want to a seq expression, I think in Python you have generators but here in F# remember that everything is an expression.
let tripleExponentialSmoothing series slen alpha beta gamma nPreds =
let mutable smooth = 0.
let mutable trend = 0.
let seasonals = initialSeasonalComponents series 12 |> Dictionary
seq {
for i in 0..(series.Length+nPreds-1) do
match i with
| 0 -> // initial values
smooth <- series |> Array.head |> float
trend <- initialTrend series slen
yield series |> Array.head |> float
| i when i >= series.Length -> // we are forecasting
let m = i - series.Length + 1
yield (smooth + float m * trend) + seasonals.[i%slen]
| _ ->
let v = series |> Array.head |> float
let lastSmooth = smooth
smooth <- alpha*(v-seasonals.[i%slen]) + (1.-alpha)*(smooth+trend)
trend <- beta * (smooth-lastSmooth) + (1.-beta)*trend
seasonals.[i%slen] <- gamma*(v-smooth) + (1.-gamma)*seasonals.[i%slen]
yield smooth + trend + seasonals.[i%slen] }
So, a sequence expressions is of the form seq { expr } and inside the expression you use yield to yield results.
As mentioned in the other answer, you are trying to mutate the list of results in the for loop, but this is not possible, because F# lists are immutable by default.
If you want to directly follow the style of the Python code, you can use mutable ResizeArray:
let tripleExponentialSmoothing series slen alpha beta gamma nPreds =
let result = ResizeArray<_>()
let mutable smooth = 0.
let mutable trend = 0.
let seasonals = initialSeasonalComponents series 12
for i in 0..(series.Length+nPreds-1) do
match i with
| 0 -> // initial values
smooth <- series |> Array.head |> float
trend <- initialTrend series slen
result.Add(series |> Array.head |> float)
| i when i >= series.Length -> // we are forecasting
let m = i - series.Length + 1
result.Add((smooth + float m * trend) + seasonals.Item(i%slen))
| _ ->
let v = series |> Array.head |> float
let lastSmooth = smooth
smooth <- alpha*(v-seasonals.Item(i%slen)) + (1.-alpha)*(smooth+trend)
trend <- beta * (smooth-lastSmooth) + (1.-beta)*trend
seasonals.Item(i%slen) <- gamma*(v-smooth) + (1.-gamma)*seasonals.Item(i%slen)
result.Add(smooth + trend + seasonals.Item(i%slen))
This is not very idiomatic F# code, but it solves your immediate problem. For a more functional solution, you can go with sequence expressions as mentioned by Gustavo and yield results one by one, but you still keep smooth and trend as mutable variables, so there probably is even nicer way of doing this - but that's hard to guess without knowing more about your algorithm.
What do the let (x = 0) in x * x translate to? A function (fun x -> x * x) 0) ? - This would make sense, as let bindings are expressions - and expressions must return values (just like functions).
Example:
let result1 =
(fun n1 -> (fun n2 ->
(fun n3 -> n1 + n2 + n3 ) 3) 2) 1
let result2 =
let n1 = 1 in
let n2 = 2 in
let n3 = 3 in
n1 + n2 + n3
let result3 =
let n1 = 1
let n2 = 2
let n3 = 3
n1 + n2 + n3
Am I right to assume that result3 is a sugared form of result2, and result2 a sugared form of result1?
Short: Do let in bindings translate to functions?
You can almost see let x = e1 in e2 as a syntactic sugar for (fun x -> e2) e1.
At the basic level, the two expressions mean the same thing - the compiler will probably compile them differently (depending on optimization levels and how it inlines things), but you could often use the second notation instead of the first one.
The one case where they differ is that ML-languages (including F#) only generalize function types written explicitly using the let keyword. This means that if you use fun, the language won't treat it as a generic function. If you want a generic function, you have to use let (and this is not just a compiler artifact, this is actually part of the language).
For example, the following uses let and it works:
let id = (fun x -> x) in ignore(id 1); ignore(id "A")
But the following does not work, because id is not a generic function:
(fun id -> ignore(id 1); ignore(id "A")) (fun x -> x)
The plain old let is just the lightweight syntax form of the verbose let … in.
From MSDN: Verbose Syntax (F#):
nested let bindings:
Lightweight syntax:
let f x =
let a = 1
let b = 2
x + a + b
Verbose syntax:
let f x =
let a = 1 in
let b = 2 in
x + a + b
The let bindings within these function don't translate to functions themselves, however. Both of these translate to identical CIL code:
f:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldc.i4.1
IL_0003: add
IL_0004: ldc.i4.2
IL_0005: add
IL_0006: ret
Note that the only function here is the outer function f. The variables a and b are evaluated as constants within the scope of f.
let x = <val> in <expr> is functionally equivalent to (fun x -> <expr>) <val>.
<expr> is an expression
<val> is a value
The in keyword is optional.
I've recently started learning F#. I'm attempting to loop through a list of functions, applying each function to a value. For example, I have:
let identity x = fun x -> x
let square x = fun x -> x * x
let cube x = fun x -> x * x * x
let functions = [identity; square; cube]
I would now like to do something like the following:
let resultList = List.map(fun elem -> elem 3) functions
where the result value would be the list [3;9;27]. However, this is not what happens. Instead, I get:
val resultList : (int -> int) list = [<fun:Invoke#3000>; <fun:Invoke#3000>; <fun:Invoke#3000>]
I guess I'm not entirely convinced that using map is the right way forward any longer, so my questions are:
Why do I not get a list of numbers?
How would return a list of numbers?
What does <fun:Invoke> mean?
Thanks very much for your help.
Daniel
Your functions aren't quite correctly defined, they're taking an extra (unused) argument and are therefore just partially applied and not evaluated as you're expecting. Besides that, your thinking is correct;
let identity2 = fun x -> x
let square2 = fun x -> x * x
let cube2 = fun x -> x * x * x
let functions = [identity2; square2; cube2]
let resultList = List.map(fun elem -> elem 3) functions;;
> val resultList : int list = [3; 9; 27]
Although I'm not an F# expert, the <fun:Invoke> would in this case seem to indicate that the value is a (partially applied) function.
Because I like to simplify where I can, you can reduce a bit on Joachim's answer by removing the fun from your functions:
let identity x = x
let square x = x * x
let cube x = x * x * x
let functions = [identity; square; cube]
printfn "%A" (List.map(fun elem -> elem 3) functions)
Gives the output [3; 9; 27]
For me this is more natural. I didn't understand why the functions themselves needed to wrap funcs, rather than simply be the function.