I'm getting an issue with the F# powerpack quotation evaluation.
open Microsoft.FSharp.Linq.QuotationEvaluation
let print x = System.Console.WriteLine(sprintf "%A" x)
type record = { x:int; y:int }
let val1 = { x = 1; y = 1; }
let val2 = { x = 1; y = 1; }
let result = val1 = val2
print result
let quote = <# let value1 = { x = 1; y = 1; }
let value2 = { x = 1; y = 1; }
let result2 = value1 = value2
result2 #>
print (quote.EvalUntyped())
The first result is true as you would expect. The second is false. Is this a bug, or am I missing something?
This looks like a bug to me. Someone from the F# team will probably give a clear answer on this :-). In the meantime, here is a simple workaround that you can use - The problem seems to be with the compilation of the = operator. You can define your own operator (or a function) and call this operator from the quoted code:
let (><) a b = a = b
let quote =
<# let value1 = { x = 1; y = 1; }
let value2 = { x = 1; y = 1; }
let result2 = value1 >< value2
result2 #>
print (quote.EvalUntyped())
Instead of generating a wrong call to the standard = operator, this will generate code that calls your custom operator (which then runs the comparison as a standard, correctly compiled F# code), so this gives the expected result.
Related
Consider a generic container like:
type Foo<'t> =
{
Foo : 't
}
This generic function works OK:
module Foo =
let inline emptyFoo () =
{
Foo = LanguagePrimitives.GenericZero
}
But this value does not:
module Foo =
let emptyFoo =
{
Foo = LanguagePrimitives.GenericZero
}
This is because the compiler infers emptyFoo to have type Foo<obj>.
However, the standard library has generic values like List.empty, so how is that achieved there?
You have to make it explicitly generic.
List.empty is implemented like this:
let empty<'T> = ([ ] : 'T list)
You could implement a List by yourself, with an empty. It looks like this.
type L<'a> =
| Null
| Cons of 'a * L<'a>
module L =
let empty = Null
let xs = Cons(1, Cons(2, L.empty))
let ys = Cons(1.0,Cons(2.0,L.empty))
So, why does L.empty in this case works in a generic way? Because the value Null has no special value attached to it. You could say, it is compatible with every other generic.
In your Record on the other hand, you always must produce a value. LanguagePrimitive.GenericZero is not some Generic value. It help so to resolve to a special zero value, and this value is determined by the other code you write.
For example
let x = LanguagePrimitives.GenericZero
is also obj
let x = LanguagePrimitives.GenericZero + 1
will be int. And
let x = LanguagePrimitives.GenericZero + 1.0
will be float. So in some case you can think of GenericZero just as a placeholder for zero for the special type you need, but the code needs to determine at this point, which type you want.
You could change your type, with an option to provide a real empty.
type Foo<'t> = {
Foo: 't option
}
module Foo =
let empty = { Foo = None }
let x = Foo.empty // Foo<'a>
let y = { x with Foo = Some 1 } // Foo<int>
let z = { x with Foo = Some 1.0 } // Foo<float>
Zero Member
Maybe you want a Zero Member on some types. For example
type Vector3 = {X:float; Y:float; Z:float} with
static member create x y z = {X=x; Y=y; Z=z}
static member (+) (a,b) = Vector3.create (a.X + b.X) (a.Y + b.Y) (a.Z + b.Z)
static member Zero = Vector3.create 0.0 0.0 0.0
static member DivideByInt(a,b) =
Vector3.create
(LanguagePrimitives.DivideByInt a.X b)
(LanguagePrimitives.DivideByInt a.Y b)
(LanguagePrimitives.DivideByInt a.Z b)
then you can write
let xs = [1;2;3]
let ys = [Vector3.create 1.0 1.0 1.0; Vector3.create 1.0 1.0 1.0]
let inline sum xs =
List.fold (fun a b -> a + b) LanguagePrimitives.GenericZero xs
let sumx = sum xs // int: 6
let sumy = sum ys // Vector3: 2.0 2.0 2.0
let's consider this code:
let getBuildDate (assembly: Assembly) : DateTime option =
let buildVersionMetadataPrefix = "+build"
let attribute = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
if attribute <> null && attribute.InformationalVersion <> null then
let value = attribute.InformationalVersion
let index = value.IndexOf(buildVersionMetadataPrefix)
if index > 0 then
let value = value.Substring(index + buildVersionMetadataPrefix.Length)
let success, timestamp = DateTime.TryParseExact(value, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.None)
if success then
Some timestamp
else
None
else
None
else
None
Is there a way to get rid of all the 'else None' statements to have only one?
On one side, I can imagine that for some people the code is more clear with all the None statements spelled out, but on the other side, coming from the C world, I see it as clutter that reduces readability.
There are many cases where you need a series of conditions to be met and all the failed cases go to one place.
If I have a list of conditions that depend on each others' success, how can I make a concise short exit without duplication.
Another approach might be to use the Option functions - each of these steps will effectively short circuit if the input from the previous step is None.
let getBuildDate (assembly: Assembly) : DateTime option =
let tryDate value =
match DateTime.TryParseExact(value, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.None) with
| true, date -> Some date
| false, _ -> None
let buildVersionMetadataPrefix = "+build"
let attribute = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
Option.ofObj attribute
|> Option.bind (fun attr -> Option.ofObj attr.InformationalVersion)
|> Option.map (fun infVer -> infVer, infVer.IndexOf buildVersionMetadataPrefix)
|> Option.filter (fun (_, index) -> index > 0)
|> Option.map (fun (infVer, index) -> infVer.Substring(index + buildVersionMetadataPrefix.Length))
|> Option.bind tryDate
Whether this is 'better' is arguable - and definitely a matter of opinion!
The other answers show how to do this using more sophisticated functional programming methods, like using computation expressions or option values. Those are definitely useful and make sense if this is something that you are doing in many places throughout your system.
However, if you just want a simple way to change the code so that the control flow is more clear (without making it more clever), I would negate the conditions. Previously, you had:
if something then
moreStuff()
Some result
else
None
You can rewrite this by returning None if not something. I think the F# coding convention in this case also allows you to remove the indentation, so it looks more like imperative early return:
if not something then None else
moreStuff()
Some result
With this, you can write your original function as follows - without any extra clever tricks:
let getBuildDate (assembly: Assembly) : DateTime option =
let buildVersionMetadataPrefix = "+build"
let attribute = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
if attribute = null || attribute.InformationalVersion = null then None else
let value = attribute.InformationalVersion
let index = value.IndexOf(buildVersionMetadataPrefix)
if index <= 0 then None else
let value = value.Substring(index + buildVersionMetadataPrefix.Length)
let success, timestamp = DateTime.TryParseExact(value, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.None)
if not success then None else
Some timestamp
A readable approach might be use a computation expression builder for Option.
type OptionBuilder() =
member _.Return v = Some v
member _.Zero () = None
member _.Bind(v, f) = Option.bind f v
member _.ReturnFrom o = o
let opt = OptionBuilder()
You can simulate an imperative style of if-then-return.
let condition num = num % 2 = 0
let result = opt {
if condition 2 then
if condition 4 then
if condition 6 then
return 10
}
Rewriting your example:
let getBuildDate (assembly: Assembly) : DateTime option = opt {
let buildVersionMetadataPrefix = "+build"
let attribute = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
if attribute <> null && attribute.InformationalVersion <> null then
let value = attribute.InformationalVersion
let index = value.IndexOf(buildVersionMetadataPrefix)
if index > 0 then
let value = value.Substring(index + buildVersionMetadataPrefix.Length)
let success, timestamp = DateTime.TryParseExact(value, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.None)
if success then
return timestamp
}
No more None.
open System
open System.Reflection
open System.Globalization
let inline guard cond next = if cond then next () else None
let getBuildDate (assembly: Assembly) : DateTime option =
let buildVersionMetadataPrefix = "+build"
let attribute = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
guard (attribute <> null && attribute.InformationalVersion <> null) <| fun _ ->
let value = attribute.InformationalVersion
let index = value.IndexOf(buildVersionMetadataPrefix)
guard (index > 0) <| fun _ ->
let value = value.Substring(index + buildVersionMetadataPrefix.Length)
let success, timestamp = DateTime.TryParseExact(value, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.None)
guard success <| fun _ ->
Some timestamp
If you can stomach the inelegance of having to write <| fun _ -> on every guard, this is an option worth considering.
Have you considered using Result<TSuccess, TError>. It is very structuring - making the code rigid and flat - and makes it possible to provide detailed error information for the step that possible fails. It's a little more code, but IMO more readable and maintainable:
let getBuildDate (assembly: Assembly) : Result<DateTime, string> =
let buildVersionMetadataPrefix = "+build"
let extractAttribute (assem: Assembly) =
match assem.GetCustomAttribute<AssemblyInformationalVersionAttribute>() with
| attrib when attrib <> null -> Ok attrib
| _ -> Error "No attribute found"
let extractDateString (attrib: AssemblyInformationalVersionAttribute) =
match attrib.InformationalVersion.IndexOf (buildVersionMetadataPrefix) with
| x when x > 0 -> Ok (attrib.InformationalVersion.Substring (x + buildVersionMetadataPrefix.Length))
| _ -> Error "Metadata prefix not found"
let toDateTime dateString =
match DateTime.TryParseExact(dateString, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.None) with
| true, timeStamp -> Ok timeStamp
| false, _ -> Error "Invalid date time format"
extractAttribute assembly
|> Result.bind extractDateString
|> Result.bind toDateTime
Usage
let optBuildDate = getBuildDate (Assembly.GetExecutingAssembly())
match optBuildDate with
| Ok date -> printfn "%A" date
| Error msg -> printfn "ERROR: %s" msg
There is an approach that I really love which is the use of an array in certain scenarios.
Example:
Instead of using something like:
if (grade >= 90) {
scale = "A";
} else if (grade >= 80) {
scale = "B";
} else if (grade >= 70) {
scale = "C";
} else if (grade >= 60) {
scale = "D";
} else {
scale = "F";
}
Use an array like:
function calculate(scores) {
var grade, scale;
let sum = 0;
for (let i = 0; i < scores.length; i++) {
sum += scores[i];
}
grade = sum / scores.length;
scale = {
[90 <= grade && grade <= 100]: "O",
[80 <= grade && grade < 90]: "E",
[70 <= grade && grade < 80]: "A",
[55 <= grade && grade < 70]: "P",
[40 <= grade && grade < 55]: "D",
[grade < 40]: "T"
};
console.log(scale.true);
}
In python could be like:
def calculate(scores: list) -> str:
grade = sum(scores) / len(scores)
print(grade)
scale = {90 <= grade <= 100: "O", 80 <=
grade < 90: "E", 70 <= grade < 80: "A",
55 <= grade < 70: "P", 40 <= grade < 55: "D",
grade < 40: "T"}
return scale.get(True)
If I have the following
type Merchant = {
Id:int;
OtherItems:int[] }
let (merchant1:Merchant) = {
Id = 1;
OtherItems = [| 1; 2 |]}
let (merchant2:Merchant) = {
Id = 2;
OtherItems = [| 1; 2 |]}
let merchants = [| merchant1;merchant2|]
And I want to flatten to the following, how do I do it?
Id = 1 OtherItems 1
Id = 1 OtherItems 2
Id = 2 OtherItems 1
Id = 2 OtherItems 2
This is what I have come up with but cant seem to get any further
let x =
merchants
|> Array.map(fun merchant -> merchant, merchant.OtherItems)
Note: I could do the long way in c# oo style but want to use functional way
Here's a way using Array.collect:
let x =
merchants
|> Array.collect (fun m ->
m.OtherItems
|> Array.map (fun x -> { Id = m.Id; OtherItems = [|x|] }))
You could make this easier to understand my first introducing a function that flattens a single merchant:
let flatten merchant = [|
for x in merchant.OtherItems do
yield { Id = merchant.Id; OtherItems = [|x|] } |]
This function has the type Merchant -> Merchant [], so it turns a single merchant into an array of merchants, one for each OtherItems.
With that flatten function, you can use the standard, built-in collect function to flatten an array of merchants:
let x' = merchants |> Array.collect flatten
Both options produce this result:
[|
{Id = 1; OtherItems = [|1|];};
{Id = 1; OtherItems = [|2|];};
{Id = 2; OtherItems = [|1|];};
{Id = 2; OtherItems = [|2|];}
|]
Use sequence generation:
let mySequence =
seq {
for merchant in merchants do
for otherItem in merchant.OtherItems do
yield {Id=merchant.Id; OtherItems=[|otherItem|]}
}
or array generation
let myArray =
[|
for merchant in merchants do
for otherItem in merchant.OtherItems do
yield {Id=merchant.Id; OtherItems= [|otherItem|]}
|]
I am trying to fetch data(type:double) from MS access below. There are number of null values stored in A&B below. is there a way to change those null values to zeros?
let query sql w=
seq{
let conn = new OleDbConnection( #"Provider=Microsoft.ACE.OLEDB.12.0;
Data Source=Portfolio.accdb;
Persist Security Info=False;" )
conn.Open()
let DAdapter = new OleDbDataAdapter(sql,conn)
let DTable = new DataSet()
let i= DAdapter.Fill(DTable)
let rowCol = DTable.Tables.[0].Rows
let rowCount = rowCol.Count
for i in 0 .. (rowCount - 1) do
yield w (rowCol.[i])
}
type Table1= {
A:double;
B:double}
let cf=query "SELECT * FROM T" (fun row ->
{
A=unbox(row.["A"]);
B=unbox(row.["B"]);})
Define a function
let toFloat = function
| null -> 0.0
| obj -> unbox obj
And then use it as follows
let cf = query "SELECT * FROM T" (fun row ->
{ A = toFloat row.["A"]
B = toFloat row.["B"] } )
Maybe, your columns in DB have different type (for example, int and double). Or try check return value with DBNull type:
let toDouble x =
if System.Convert.IsDBNull(x) then 0.0
else System.Double.Parse(x.ToString())
To check I create that table:
And with your code:
open System.Data
open System.Data.OleDb
let toDouble x =
if System.Convert.IsDBNull(x) then 0.0
else System.Double.Parse(x.ToString())
let query sql w=
seq{
let conn = new OleDbConnection( #"Provider=Microsoft.ACE.OLEDB.12.0;
Data Source=F:/Portfolio.accdb;Persist Security Info=False;" )
conn.Open()
let DAdapter = new OleDbDataAdapter(sql,conn)
let DTable = new DataSet()
let i = DAdapter.Fill(DTable)
let rowCol = DTable.Tables.[0].Rows
let rowCount = rowCol.Count
for i in 0 .. (rowCount - 1) do
yield w (rowCol.[i])
conn.Close()
}
type Table1= { A:double; B:double }
let cf = query "SELECT * FROM T" (fun row -> { A = toDouble row.["A"]; B = toDouble row.["B"] } )
cf |> Seq.iter(fun x -> printfn "%A" x)
Result:
{A = 1.0;
B = 2.2;}
{A = 3.0;
B = 0.0;}
{A = 4.0;
B = 0.0;}
Is there an idiomatic way in F# to look ahead in a list/seq/array and use the information learned in the processing of the current item? In my scenario it would also be necessary to mutate (or otherwise store the fact it was changed) the ahead item so it is processed correctly in turn. I'm implementing some rather silly business rules and such a pattern or technique would be useful.
Right now I'm using an accumulator to store the information and then mutating items of an array as I process each. This feels a bit clumsy as you can see in the simplified example below. The actual business rules for the problem I'm solving are more complex so I rather not trudge down this path if there is a better way. Essentially, I want to get rid of graceMonths in the Acc type and instead solve those months by looking ahead in the list/seq/array.
The mock example: Workers get some type of bonus when they reach a desired level of production each month. If they fail to meet the desired level they can make up for it by exceeding the level in following months. Likewise, they can bank excess production for use in future months where they fall short. The following script shows an example.
type CalendarMonth =
{ year : int
month : int }
type InMonth =
{ month : CalendarMonth
prodCount : int }
type OutMonth =
{ month : CalendarMonth
prodCount : int
borrowedFrom : InMonth list
metProd : bool }
type OutMonthAcc =
{ outMonth : OutMonth
notUsed : InMonth list }
type IndexOutMonth =
{ index : int
outMonth : OutMonth }
type Acc =
{ index : int
graceMonths : IndexOutMonth list
bankedProd : InMonth list
arrRef : OutMonth array }
type GraceAcc =
{ processed : IndexOutMonth list
notUsed : InMonth list }
let createMonth y m c =
{ InMonth.month =
{ year = y
month = m }
prodCount = c }
let toOutPutMonth (x : InMonth) =
{ month = x.month
prodCount = x.prodCount
borrowedFrom = []
metProd = false }
let toSimple (x : OutMonth) = sprintf "year: %i, month: %i, metProd: %b" x.month.year x.month.month x.metProd
let solveWithBanked desiredProd bank m =
let useProd (acc : OutMonthAcc) inMonth =
let m = acc.outMonth
if m.metProd then
{ acc with notUsed = inMonth :: acc.notUsed }
else
let borrowed = m.borrowedFrom |> List.sumBy (fun x -> x.prodCount)
let needed = desiredProd - (m.prodCount + borrowed)
match inMonth.prodCount with
| x when x < needed ->
{ outMonth = { m with borrowedFrom = inMonth :: m.borrowedFrom }
notUsed = acc.notUsed }
| x when x > needed ->
let newInMonth = { inMonth with prodCount = inMonth.prodCount - needed }
let newOutMonth =
{ m with borrowedFrom = newInMonth :: m.borrowedFrom
metProd = true }
{ outMonth = newOutMonth
notUsed = newInMonth :: acc.notUsed }
| _ ->
{ outMonth =
{ m with borrowedFrom = inMonth :: m.borrowedFrom
metProd = true }
notUsed = acc.notUsed }
bank |> List.fold useProd { outMonth = m
notUsed = [] }
let solveGrace desiredProd bank (graceLst : IndexOutMonth list) =
let useBank acc iOutMonth =
let result = iOutMonth.outMonth |> solveWithBanked desiredProd acc.notUsed
if result.outMonth.metProd then
let iMonth =
{ index = iOutMonth.index
outMonth = result.outMonth }
{ processed = iMonth :: acc.processed
notUsed = result.notUsed }
else { acc with processed = iOutMonth :: acc.processed }
graceLst
|> List.sortBy (fun x -> x.index)
|> List.fold useBank { processed = []
notUsed = bank }
let solve desiredProd acc m =
match m.prodCount < desiredProd with
| true -> // less
let result = m |> solveWithBanked desiredProd acc.bankedProd
if result.outMonth.metProd then
acc.arrRef.[acc.index] <- result.outMonth
{ acc with index = acc.index + 1
bankedProd = result.notUsed }
else
let iMonth =
{ IndexOutMonth.index = acc.index
outMonth = m }
{ acc with index = acc.index + 1
graceMonths = iMonth :: acc.graceMonths }
| false -> // greater
let newM =
{ index = acc.index
outMonth = { m with metProd = true } }
let newIn =
{ InMonth.month = m.month
prodCount = m.prodCount - desiredProd }
let result = acc.graceMonths |> solveGrace desiredProd (newIn :: acc.bankedProd)
let solved, unsolved = result.processed |> List.partition (fun x -> x.outMonth.metProd)
newM :: solved |> List.iter (fun x -> acc.arrRef.[x.index] <- x.outMonth)
{ acc with index = acc.index + 1
graceMonths = unsolved
bankedProd = result.notUsed }
let jan = createMonth 2013 01 4
let feb = createMonth 2013 02 4
let mar = createMonth 2013 03 6
let apr = createMonth 2013 04 7
let may = createMonth 2013 05 4
let jun = createMonth 2013 06 4
let arr =
jan :: feb :: mar :: apr :: may :: jun :: []
|> Array.ofList
|> Array.map toOutPutMonth
arr |> Array.fold (solve 5) { index = 0
graceMonths = []
bankedProd = []
arrRef = arr }
let result =
arr
|> Array.map toSimple
|> List.ofArray
The value of result should show all months met production except June. Is this the right approach in F# or is there a better way?
This is the approach I would try here:
Calculate the differences between the expected and actual amounts for each month upfront,
Split the months into three groups - the ones that are below the quota, above the quota and ones that exactly make the quota,
Attempt to balance the ones below the quota with the ones above the quota.
The first two points seem pretty self-explanatory to me, as for the third one, here's the draft of the balance function and an example usage:
let (|Lt|Eq|Gt|) (a, b) =
if a = b
then Eq
elif a > b then Gt else Lt
let rec balance below above balanced =
match below, above with
| (x, required)::xs, (y, available)::ys ->
match required, available with
| Lt -> balance xs ((y, available - required) :: ys) (x::balanced)
| Eq -> balance xs ys (x::y::balanced)
| Gt -> balance ((x, required - available) :: xs) ys (y::balanced)
| _, _ ->
below, above, balanced
balance [("a", 4); ("b", 1)] [ ("c", 2); ("d", 2) ] [ "e" ]
balance [("a", 1); ("b", 1)] [ ("c", 2); ("d", 2) ] [ "e" ]
Essentially you walk the two lists in parallel, "taking" from the one and "adding" to the other, until you run out of either one. What remains is the best attempt at making things balanced.
Typically you want to use collection APIs like the List module when writing F# code, but it's useful to remember that you can always fall back to "raw" recursion when your use case doesn't seem to fit into existing schemes.