Can you unwrap Discriminated Unions without a signature file? - f#

Designing with Single-Type-Case DUs
given
type DoB = | DoB of System.DateTime
let DoB (dt:DateTime) = // shadow constructor
if(dt.Year>1914) // business defines what a min Date of Birth should be
then Some(DoB dt)
else None
And I see via Answers to wrapping Multi-case DU's you can do the constructor shadowing without an .fsi file very easily.
By Unwrapping I mean let value (EmailAddress e):string = e from the article (which would have to be in the .fsi file or applied to this DoB type would look like
let value (DoB dob):DateTime = dob if we had an .fsi file.
can you do the same somehow for unwrapping that was done with the constructor?
can I somehow define an unwrapper or augmentation of some sort?

If I understand what you mean by unwrapping, you could use an active pattern:
//File1.fs
let (|DoB|) (DoB dt) = dt
//File2.fs
let dob = DoB DateTime.Now //using `DoB` "constructor" function
match dob with
| Some (DoB dt) -> //using `DoB` active pattern
printfn "DOB: %A" dt
| None ->
printfn "Not a DOB"
This works, without shadowing the function of the same name, because active patterns live in a separate naming scope.

Related

Dapper SetValue on F# Union type not being called

My research on this seems to conclude a bug in dapper, but I'm hoppign I'm missing something simple.
I have a union type
type PrimaryKey<'x> =
| Id of int
| EmptyPrimaryKey
And I want to be able to map that to int columns in SQL.
My custom type handler is below:
type PrimaryKeyHandler<'X>() =
inherit SqlMapper.TypeHandler<PrimaryKey<'X>>()
override _.SetValue(param, value) =
printfn "Running set value"
let valueOrNull =
match value with
| PrimaryKey.Id id ->
box id
| EmptyPrimaryKey ->
null
param.Value <- valueOrNull
override _.Parse value =
if isNull value || value = box DBNull.Value
then EmptyPrimaryKey
else Id (value :?> int)
_.Parse is working correctly when I'm using Select queries, so all good there.
However when I'm trying to Insert a value, .SetValue does not seem to be being called at all and the program is dying with the type cannot be used as a parameter value
And when dumping out the values that's going into the query, it is indeed a PrimaryKey rather than an integer. And no printfn statements or breakpoints are being hit.
This doesn't seem to be a super uncommon problem but I haven't found a clear solution yet.

let vs member for private functions, in F#

Let's consider this code:
type TransactionTypes =
| TransactionType1
| TransactionType2
type Test() =
let mutable lastTransactionType1 = DateTime.MinValue
let mutable lastTransactionType2 = DateTime.MinValue
let getLastTransaction transaction =
match transaction with
| TransactionType1 -> lastTransactionType1
| TransactionType2 -> lastTransactionType2
let updateLastTransaction transaction =
match transaction with
| TransactionType1 -> lastTransactionType1 <- DateTime.UtcNow
| TransactionType2 -> lastTransactionType2 <- DateTime.UtcNow
Now (with the understanding that I'm still learning F#), I would like to clarify a couple things:
Something like:
let a = DateTime.Now
does a permanent binding, so 'a' will always be the same time on subsequent uses.
But, my understanding is that if there is a parameter, like:
let a anyParameter = DateTime.Now
will be re-evaluated every time due to the presence of the parameter. Is that correct?
In the code above, the two let statements (getLastTransaction and updateLastTransaction) are private to the type (Test)
I could also have implemented them as:
member private this.getLastTransaction = ...
member private this.updateLastTransaction = ...
Is there any reason, for private functions to prefer let vs. member private this?
"let mutable" already implies the this. so the fields are accessible by both forms.
So, what is the advantage of one form vs. the other?
When you are working with members, F# inherits a lot of things from the .NET object model. A .NET object can have a couple of different things:
Fields - those are storing a value (just like fields of a record). They can be mutable or immutable.
Methods - those can be invoked with zero or more arguments (like functions)
Properties - those have no arguments (like fields); they can be read or written, but when this happens, some code is invoked. A property is basically a pair of getter and setter methods.
In F#, some of this is less visible. However, let corresponds to a field and member with arguments corresponds to a method. Your tricky case is a member without arguments. For example:
type A() =
member x.Foo = printfn "Hi"; 42
Will Hi be printed only once, or will it be printed each time you access Foo? To answer, it's useful to know that Foo is a property with a getter. The above is actually a syntactic sugar for the full version:
type A() =
member x.Foo
with get() = printfn "Hi"; 42
Now you can see that there is a method behind the Foo property! Each time you access Foo, the compiler will generate a call to the get() method, so Hi will be printed repeatedly.
In addition to Tomas' answer:
let mutable lastTransactionType1 = DateTime.MinValue
is equivalent in C# to:
internal DateTime lastTransactionType1 = DateTime.MinValue;
and
member private this.getLastTransaction ...
is the same IL as far as IL is concerned with
let getLastTransaction ...
In equivalent C#, both are
internal DateTime getLastTransactionMember(TransactionTypes transaction)
{
if (transaction.Tag != 1)
{
return lastTransactionType1;
}
return lastTransactionType2;
}
But for using F# in an idiomatic way, you would want to go with let.
There's also a difference in that member does let you use the methods in bindings before their declaration, which might be useful in some cases (read: hacks)
let getType1 = this.getLastTransactionMember TransactionType1 //this compiles
member private this.getLastTransactionMember transaction =
match transaction with
| TransactionType1 -> lastTransactionType1
| TransactionType2 -> lastTransactionType2

How to disable ToString on records

I have a record type which occurs quite often in a nested complex data structure. Because the record type has an automatically generated ToString the ToString of my bigger structure becomes way to confusing and I do not care for the string representation of my record.
So I want to have an empty string as representation for my record. Overriding ToString seems to not do anything, using StructuredFormatDisplay does not work with empty strings since it requires an input of the form "Text {Field} Text". Right now I have
[<StructuredFormatDisplay("{}")>]
type MyRecord
{ 5 fields... }
override __.ToString () = ""
But this results in The method MyRecord.ToString could not be found.
So what is the correct way to not have a string representation for a record type?
The comments all provide correct information about how to achieve your goal. Pulling it all together, here's what I would do in a real-world scenario where I wanted a record type to always have the empty string as its string representation:
open System
[<StructuredFormatDisplay("{StringDisplay}")>]
type MyRecord =
{
A: int
B: string
C: decimal
D: DateTime
E: Guid
}
member __.StringDisplay = String.Empty
override this.ToString () = this.StringDisplay
This way, regardless of what technique is used to print the record, or if its ToString method is used by an external caller, the representation will always be the same:
let record = {A = 3; B = "Test"; C = 5.6M; D = DateTime.Now; E = Guid.NewGuid()}
printfn "Structured Format Display: %A" record
printfn "Implicit ToString Call: %O" record
printfn "Explicit ToString Call: %s" <| record.ToString()
This prints:
Structured Format Display:
Implicit ToString Call:
Explicit ToString Call:
One thing to keep in mind is that this will even override the way the record is displayed by F# interactive. Meaning, the record evaluation itself now shows up as:
val record : MyRecord =

Unwrap F# single-case discriminated union tuple type

We can unwrap type like type Address = Address of string using unwrapping function like
let unwrapAddress (Address a) = a
let addr = Address "sdf"
let str = unwrapAddress addr
so str will be of type string, but if there is type like this approach willn't work:
type Composite = Composite of integer:int * someStr:string
let unwrap (Composite c) = c
will produce error
let unwrap (Composite c) = c;;
------------^^^^^^^^^^^
error FS0019: This constructor is applied to 1 argument(s) but expects 2
Can I somehow unwrap composite types to a simple tuple?
In your case, you can write:
type Composite = Composite of int * string
let unwrap (Composite (a, b)) = a, b
which corresponds to:
let unwrap x =
match x with
| Composite (a, b) -> a, b
What's happening here is that F# allows you to deconstruct function arguments inline using arbitrarily complex pattern matching. This is often mentioned when introducing single case DU's, but it's rarely followed to the conclusion, which leads people to believe single case DU's are somehow special that way.
In fact, you can use it when you have multiple cases (as long as each case binds the same set of variables):
type Composite = Composite of int * string | JustString of string
let unwrapString (Composite (_, s) | JustString s) = s
But most of the time, you'd pattern match on simpler types, like tuples:
let f (a, b, c) = ...
or even more curiously:
let f () = ...
Here () is a pattern match on the lone value of unit type - rather than some kind of "visual marker for a parameterless function", as it's often described.
You defined the type as a single-case discriminated union with named fields:
type Composite = Composite of integer:int * someStr:string
When defined in this way, the fields of the union case are not a simple tuple. They get treated in a special way and, for example, the names are used as property names in compiled code. The pattern matching does not automatically turn the elements into a tuple and so you have to unwrap them separately:
let unwrap (Composite(i, s)) = i, s
However, you can also define single-case union where the field is an ordinary tuple. (Note that you need the parentheses around the tuple type - otherwise, it also ends up being treated in a special way, except that the items will be compiled as Item1 and Item2.)
type Composite = Composite of (int * string)
With this definition, your unwrap function will work fine and extract the tuple value:
let unwrap (Composite c) = c
You can also use a nested pattern to get the number and the string like in the previous case:
let unwrap (Composite(i, s)) = i, s
The fact that this behaves differently depending on whether you write A of (T1 * T2) or whether you write A of T1 * T2 is a bit subtle - the two probably need to be distinguished just so that the compiler knows whether to compile the fields as two separate fields or as one field of type System.Tuple<T1, T2>. I cannot quite imagine any other case where the difference would matter.
These all work for me. It's your matching syntax, that most often you'll find used with match statements, but it's on the l.h.s. of an assignment. Possibly, this makes the most sense, initially, for tuples, but you can use this with any structure.
let (a,b) = (1,2)
let (x,_) = (4,5)
Two other interesting things to try:
let (head::tail) = [1;2;3;4]
FSI responds warning FS0025: Incomplete pattern matches on this expression. For example, the value '[]' may indicate a case not covered by the pattern(s).
"That's true," you reason aloud. "I should express it as a match and include an empty list as a possibility". It's better to bubble these kinds of warnings into fully bonafide errors (see: warn as error e.g. --warnaserror+:25). Don't ignore them. Resolve them through habit or the compiler enforced method. There's zero ambiguity for the single case, so code-on.
More useful + interesting is the match syntax on the l.h.s. of a function assignment. This is pretty cool. For pithy functions, you can unpack the stuff inside, and then do an operation on the internals in one step.
let f (Composite(x,y)) = sprintf "Composite(%i,%s)" x y
f (Composite(1,"one"))
> val it : string = "Composite(1,one)"
About your code:
type Address = Address of string //using unwrapping function like
let unwrapAddress (Address a) = a
let addr = Address "sdf"
let str = unwrapAddress addr
type Composite = Composite of integer:int * someStr:string
let unwrap (Composite(c,_)) = c
let cval = Composite(1,"blah")
unwrap cval
Workaround:
let xy = Composite(1,"abc") |> function (Composite(x,y))->(x,y)
... but the nicer way, assuming you want to keep the named elements of your single case DU would be...
let (|Composite|) = function | Composite(x,y)->(x,y)
let unwrap (Composite(x)) = x
let unwrap2 (Composite(x,y)) = (x,y)
... not strictly decomposing through a single case DU, but decomposing through a single-case Active Pattern
lastly, you could attach a method to the Composite structure...
module Composite =
let unwrap = function | Composite(x,y)->(x,y)
One of the best discussions about using this technique is over here
Also, check out the signature that unwrap gives us: a function that takes a Composite (in italics), and returns an int (in bold)
Signature -- val unwrap : Composite -> int

Why I'm getting null for a string in F#?

One of the benefits of the type system on F# is avoid a null exception... or that was something I believe... because I'm getting a null problem:
[<CLIMutable>]
type Customer = {
[<AutoIncrement>] id:option<int64>
code:string
name:string
}
I'm running a SQL code:
let SqlFTS<'T>(table:string, searchTable:string, query:string) =
use db = openDb()
let sql = sprintf "SELECT * FROM %s WHERE id in (SELECT docid FROM %s WHERE data MATCH %A)" table searchTable query
printfn "%A" sql
db.SqlList<'T>(sql) |> Seq.toArray
testCase "Customers" <|
fun _ ->
let rows = GenData.genCustomers(50)
Customers.insert(rows)
isEqual "Failed to insert" 50L (DB.SqlCount<Customers.Customer>())
//Until here, it works
let c = Customers.byId(1L)
printfn "%A" c
//Customers.byId return me a record with all the properties as NULLS!
//Then c.name is null, and the code above fail.
let rows = Customers.searchCustomers(c.name)
This was very unexpected. Why I can get a record with all values to null?
Let's start with line 1:
[<CLIMutable>]
The docs for CLIMutable state
Adding this attribute to a record type causes it to be compiled to a Common Language Infrastructure (CLI) representation with a default constructor with property getters and setters.
That default constructor means the fields will be initialized to default values. The default value for string is null. That's valid to the CLR and it's valid to C# and VB.NET. You may not be able to call the default ctor from F#, but pretty much anyone else can.
Welcome to interop; it can be a pain.

Resources