tail recursion and Boolean operators - f#

I am currently learning F# on my own (via the try f# site).
I have the following (imho) tail-recursive function for existential quantification of a unary predicate (int->bool).
let rec exists bound predicate =
if (bound<0) then false
elif predicate(bound) then true
else exists (bound-1) predicate
Now this function can also be written as
let rec exists bound predicate = (bound+1>0) && (predicate(bound) || exists (bound-1) predicate)
However, the second implementation is not tail-recursive. The question is whether or not the compiler will optimize it to tail-recursive?
How is the situation for even simpler (ok, it is a bit silly) examples, say
let rec hasNoRoot f =
if (f x = 0) then false
else hasNoRoot (fun x -> f (x+1))
versus
let rec hasNoRoot f = (f 0 <> 0) && (hasNoRoot (fun x-> f(x+1)))
in the second example, in order to recognize the function (its description actually) as tail-recursive, the compiler only needs to "know" that in order to evaluate a conjunction, not necessarily both conjuncts have to be evaluated.
thanks for any advice

I compiled the second versions of your 'exists' and 'hasNoRoot' functions with VS2012 (F# 3.0) and optimizations on, then checked the IL produced by the compiler using .NET Reflector. The compiler does optimize the 'hasNoRoot' function, but unfortunately, does not optimize the 'exists' function. It seems like a reasonable optimization though, so perhaps it will be added to the next version of the compiler.
For posterity, here's what the compiler generated:
.method public static bool exists(int32 bound, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, bool> predicate) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = { new int32[int32(0x2)] { int32(0x1), int32(0x1) } }
.maxstack 8
L_0000: nop
L_0001: ldarg.0
L_0002: ldc.i4.1
L_0003: add
L_0004: ldc.i4.0
L_0005: ble.s L_001c
L_0007: ldarg.1
L_0008: ldarg.0
L_0009: callvirt instance !1 [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, bool>::Invoke(!0)
L_000e: brfalse.s L_0012
L_0010: ldc.i4.1
L_0011: ret
L_0012: ldarg.0
L_0013: ldc.i4.1
L_0014: sub
L_0015: ldarg.1
L_0016: starg.s predicate
L_0018: starg.s bound
L_001a: br.s L_0001
L_001c: ldc.i4.0
L_001d: ret
}

Related

F# Or-Tools Sat Solver

I am experimenting with F# and want to do some constraint programming where I use Or-Tools. I have previously used the package together with Python, but I can’t get it to work with F#.
I follow the C# example: https://developers.google.com/optimization/cp/cp_solver#c_5
But get an error when try to add a constraint:
So this is kind of annoying, but it's how consuming operators that were overloaded in C# from F# works.
The reason why you couldn't use != like this is because:
The operator != is (and this is unusual) overloaded in C# as a static operator on the LinearExpr class.
The operator != compiles down to op_Inequality, but op_Inequality in F# is <>, not !=
F# already defines <> as a generic operator that accepts any member that satisfies the equality constraint, which LinearExpr does
The defined operator <> resolves correctly, and produces a bool, which is incompatible with model.Add because it doesn't expect a bool
The solution is to explicitly qualify your access to the operator like so:
LinearExpr.(<>) (x, y)
Note that because it takes tupled arguments in its definition, you must also tuple your arguments and you can't use it like a "normal" operator.
Here is the full F# solution, with a few small tweaks to make it idiomatic:
#r "nuget: Google.OrTools"
open Google.OrTools.Sat
let model = CpModel()
// Creates the variables.
let num_vals = 3L;
let x = model.NewIntVar(0L, num_vals - 1L, "x")
let y = model.NewIntVar(0L, num_vals - 1L, "y")
let z = model.NewIntVar(0L, num_vals - 1L, "z")
// Creates the constraints.
model.Add(LinearExpr.(<>) (x, y))
// Creates a solver and solves the model.
let solver = CpSolver();
let status = solver.Solve(model)
if status = CpSolverStatus.Optimal then
printfn $"x = {solver.Value(x)}"
printfn $"y = {solver.Value(y)}"
printfn $"z = {solver.Value(z)}"
A way to make this a bit nicer from F# is to define a module of operators that map to the LinearExpr operators like so:
module LinearExprOperators =
let ( ^<> ) (x: LinearExpr) (y: LinearExpr) = LinearExpr.(<>) (x, y)
let ( ^= ) (x: LinearExpr) (y: LinearExpr) = LinearExpr.(=) (x, y)
Then you can use those operators instead. Another annoyance is that it appears that + and - and * work just fine, because the F# type doesn't produce a different type like bool.
So in short, this particular API is a little annoying to use from F#.

order of operators in F# query expression

Does the order of query expression operators matter? Idk, but sometimes (in some selections) it does, but sometimes it doesn't (or maybe it does but implicitly handles some particular occasions).
Is is mandatory that select operator must go last? in pretty much every combination it complains if you don't write it as a last statement, but in case of take n, this operator can go after select
I'm just interested in how the process of execution acts?
This brings me to another question. If it iterates over Iterable collection, and thus on the first iteration it selects some one(first) value, how order works on that one(first) value? it would be clear if first it returned sequence, and then executed order on that sequence.. but seems like it executes sortBy at every iteration (?). I'm interested in what the design of the executed algorithm is.
Here is my example of Query Expression.
let sq = query {
for p in datasource do
where p.age>20
sortBy p.age
select p
}
Explanations would be greatly appreciated.
Thanks
We don't need to guess, we can find out.
let sample = Seq.init 10 (fun i -> i * 10) |> Seq.map (fun i -> { age = i })
let sq = query {
for p in sample do
where (p.age > 20)
sortBy p.age
select p
}
sq |> Seq.toList |> ignore
The generated IL (cleaned up) looks like
IL_004e: newobj instance void Program/sq#16::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder)
IL_0053: callvirt instance [...] For<class Program/Person,
IL_005d: callvirt instance [...] Where<class Program/Person,
IL_0067: callvirt instance [...] SortBy<class Program/Person,
IL_0071: callvirt instance [...] Select<class Program/Person,
Suppose we change the order of sortBy
let sq = query {
for p in sample do
sortBy p.age
where (p.age > 20)
select p
}
The new IL will be:
IL_006c: callvirt instance [...] For<class Program/Person,
IL_0076: callvirt instance [...] SortBy<class Program/Person,
IL_0080: callvirt instance [...] Where<class Program/Person,
IL_008a: callvirt instance [...] Select<class Program/Person,
You can clearly see that it follows the exact order you define the query in.
This wouldn't matter for T-SQL comprehensions because the query will be translated by an Expression visitor, but for object queries, query expressions are pretty much just syntactic sugar for you.
Method #2:
You can extend the query expression module to include an operator for side-effects. This is simply a port of Interactive Extensions' DoAction method.
module QueryExtensions =
type QueryBuilderEx() =
inherit Linq.QueryBuilder()
[<CustomOperation("doAction", MaintainsVariableSpace = true)>]
member __.Do(source : Linq.QuerySource<'T,System.Collections.IEnumerable>, action) =
new Linq.QuerySource<'T,System.Collections.IEnumerable>(source.Source |> Seq.map (fun v -> action(v); v))
let query = QueryExtensions.QueryBuilderEx()
Now you can debug the order like so
let sq = query {
for p in sample do
sortBy p.age
where (p.age > 20)
doAction (printfn "Next -> %A")
select p
}
If you move it above the where, you'll see that it reflects those records before filtering.

c# to f# conversion with interfaces and linq statements

I'm trying to convert this c# method that uses interfaces and Linq to f#:
public static IEnumerable<ModelEngines> CurrentEngineBuilds(IEnumerable<CurrentModels> thisYearModels, DateTime startRunDate, DateTime endRunDate)
{
var engineOptions =
currentModelYear.SelectMany(c => c.Engines)
.Where(e => e.EngineProdStartDate >= startRunDate & e.EngineProdStopDate <= endRunDate);
return engineOptions;
}
In the method above, I'm returning a collection of engineOptions - type is IEnumerable. I'm filtering the collection so that the collection only has engineOptions with a certain production range from the current model year.
I have this rough, non-working, translation below:
let CurrentEngineBuilds : <IEnumerable<ModelEngines>> (thisYearModels : IEnumerable<CurrentModels>) (startRunDate : DateTime) (endRunDate : DateTime) =
query {
for engineOptions in currentModelYear.engineOptions do
where (engineOptions.EngineProdStartDate >= startRunDate and engineOptions.EngineProdEndDate >= endRunDate )
select (engineOptions)
}
engineOptions
This task has become more complicated than I had anticipated. I've gone through a few f# tutorials to get through the basics, but it seems anything to do with interfaces and/or linq is pretty difficult.
Some issues I have:
How the heck to you work with interfaces in f#?
Is there an f# equivilent of the SelectMany method?
Any tips on how to do this c# to f# conversion?
IEnumerable<'T> is named seq<'T> in F#. I don't see any reason to use LINQ query expressions in this case; the more idiomatic F# translation would use the Seq module:
let CurrentEngineBuilds thisYearModels startRunDate endRunDate =
thisYearModels
// v--- SelectMany
|> Seq.collect (fun c -> c.Engines)
// v--- Where
|> Seq.filter (fun e ->
e.EngineProdStartDate >= startRunDate && e.EngineProdStopDate <= endRunDate)
If the type of thisYearModels is not deduced automatically, you can annotate it in the function signature:
let CurrentEngineBuilds (thisYearModels:seq<CurrentModels>) startRunDate endRunDate = ...
or in the body:
let CurrentEngineBuilds thisYearModels startRunDate endRunDate =
(thisYearModels:seq<CurrentModels>)
|> Seq.collect (fun c -> c.Engines)
|> Seq.filter (fun e ->
e.EngineProdStartDate >= startRunDate && e.EngineProdStopDate <= endRunDate)
// or
let CurrentEngineBuilds thisYearModels startRunDate endRunDate =
thisYearModels
|> Seq.collect (fun (c:CurrentModels) -> c.Engines)
|> Seq.filter (fun e ->
e.EngineProdStartDate >= startRunDate && e.EngineProdStopDate <= endRunDate)
You can actually use LINQ in F# without any problems whatsoever. Here's an almost direct port of your original sample (I'm assuming that currentModelYear is a type and you meant thisYearModels)
open System.Linq
let currentEngineBuilds(thisYearModels:seq<CurrentModels>, startRunDate, endRunDate) =
let engineOptions =
thisYearModels
.SelectMany(fun e -> e.Engines)
.Where(fun e -> e.StartDate >= startRunDate && e.StopDate <= endRunDate)
engineOptions // return keyword not required
For the purposes of this post, you can think of seq<T> as a shorthand for IEnumerable<T>.
Having said that, I think that you'll find the Seq module a better fit for F# as it's designed to take advantage of F# language features such as Tuples, and can assist in the type inference process.
The |> or "pipe" operator is F#'s idiomatic way of applying a function to a value.
v |> f is the same as f v as pointed out earlier.
Monadic chaining, on the other hand, is quite another matter entirely. You're using monadic chaining in the query computation expression in the original post, and it is also idiomatic.
Hope that helps to keep those two (fairly complex) concepts apart in your understanding! :)

F# mutable function arguments

Is there a way to have mutable function arguments in F#, that would allow something like
let mutable i = 9
let somefun n = n <- 12; ()
somefun i
(* *not* a real-world example *)
I do understand that this can be made to work by wrapping it into a record type
type SomeRec = { mutable i: int }
let ri = { i = 9 }
let someotherfun r = r.i <- 12; ()
and that this can be done in a similar fashion for class members. However, even after browsing through the whole F# Language Specification (yes, I did!), there seems to be no syntax to allow the first case, and the compiler appears to be quite unhappy about my trying this. I was hoping there would be some sort of type annotation, but mutable cannot be used in such.
I also know that I should not be doing this sort of thing in the first place, but the first case (int binding) and the second (record type) are semantically identical, and any such objection would hold for both cases equally.
So I think that I am missing something here.
You can use ref as arguments
let v = ref 0
let mutate r =
r := 100
mutate v
printfn "%d" !v
Or byref keyword
let mutable v = 0
let mutate (r : byref<_>) =
r <- 100
mutate &v
printfn "%d" v
Use byref keyword which is equivalent to C# ref.
See Passing by reference.

Is this the F# Builder bug or my misunderstanding?

When I tried the console programming, I received unexpected result.
open System
let printSomeMessage =
printfn "Is this the F# BUG?"
[<EntryPoint>]
let main args =
if args.Length = 2 then
printSomeMessage
else
printfn "Args.Length is not two."
0
The printSomeMessage function was included in .cctor() function. Here is IL DASM result.
.method private specialname rtspecialname static
void .cctor() cil managed
{
// Code size 24 (0x18)
.maxstack 4
IL_0000: nop
IL_0001: ldstr "Is this the F# BUG\?"
IL_0006: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5<class [FSharp.Core]Microsoft.FSharp.Core.Unit,class [mscorlib]System.IO.TextWriter,class [FSharp.Core]Microsoft.FSharp.Core.Unit,class [FSharp.Core]Microsoft.FSharp.Core.Unit,class [FSharp.Core]Microsoft.FSharp.Core.Unit>::.ctor(string)
IL_000b: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormatLine<class [FSharp.Core]Microsoft.FSharp.Core.Unit>(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<!!0,class [mscorlib]System.IO.TextWriter,class [FSharp.Core]Microsoft.FSharp.Core.Unit,class [FSharp.Core]Microsoft.FSharp.Core.Unit>)
IL_0010: dup
IL_0011: stsfld class [FSharp.Core]Microsoft.FSharp.Core.Unit '<StartupCode$FSharpBugTest>'.$Program::printSomeMessage#3
IL_0016: pop
IL_0017: ret
} // end of method $Program::.cctor
So, its execution result is like this.
Is this the F# BUG?
Args.Length is not two.
Am I missing some grammar or F# characteristic? Or F# builder’s BUG?
No it's a bug in your code. You need to add parentheses after "printSomeMessage", otherwise printSomeMessage is a simple value rather than a function.
open System
let printSomeMessage() =
printfn "Is this the F# BUG?"
[<EntryPoint>]
let main args =
if args.Length = 2 then
printSomeMessage()
else
printfn "Args.Length is not two."
0
Simple values are initialized in the constructor of a module, so you see your code being called when the module is initialized. This is logical when you think about it, the normal case of simple values would be binding a string, integer, or other literal value to an identifier. You would expect this to happen a start up. i.e. the following will be bound at module start up:
let x = 1
let y = "my string"

Resources