Generically add field to anonymous record using a function - f#

I would like to be able to take an arbitrary record as a parameter and return an anonymous record with a field added using the copy-and-update syntax.
For example, this works:
let fooBar =
{| Foo = ()
Bar = () |}
let fooBarBaz = {| fooBar with Baz = () |}
But I would like to do this:
let fooBar =
{| Foo = ()
Bar = () |}
let inline addBaz a = {| a with Baz = () |} (* The input to a copy-and-update expression that creates an anonymous record must be either an anonymous record or a record *)
let fooBarBaz = addBaz fooBar
Is there a way to do this in F#?

No, that's not possible.
Think about it, if that function was possible, what would be the type ?
Is it something that "fits" into existing F# type system?
The type should be something like val addField: x: {| FieldName<1>: 't1; FieldName<2>: 't2; ... FieldName<n>: 'tn;|} -> {| FieldName<1>: 't1; FieldName<2>: 't2; ... FieldName<n>: 'tn; Baz: unit |}
Clearly something like that's not representable in F# type system.
UPDATE
It was mentioned that adding a record constraint would allow this but this is quite far from reality. A record constraint would just filter the argument to be a record but the problem which remains is how do the type system express that the function takes a type ^T when ^T : record and returns something like ^U when ^U : ^T_butWithAnAdditionalField
Also, on the SRTP side there is a way to "read" a field by adding a get_FieldName constraint but not to write, moreover the possibility to read a field allow us to read a field of a known name, not any name.
Conclusion: F# type system is very far away from allowing to express stuff like this and the SRTP mechanism is not there either.
Allowing an "is record" constraint shouldn't be that complicated but it won't solve anything here.

This is currently not possible. You can find a discussion about it in this proposal:
#807: Allow record to be a generic constraint
If I understand correctly, the solution they mention in the proposal is that you have to be able to constrain the input type to be record. Something that is currently not possible.
But as Gus points out in his answer, a second consideration is that you also need to have a way to specify the output type because the output type depends on the input type.
UPDATE:
There is some discussion going on whether the linked to proposal is relevant or not or if the conclusion I draw from it it correct. First of all, I do not work on the compiler, so I don't know what the biggest hurdle would be. But below analysis does not seem unreasonable to me.
First, let's get rid of generics to have a feel for what's going on:
type Foo =
{ Foo: int }
let addBaz (x: Foo) = // Foo -> {| Baz: unit; Foo: int|}
{| x with Baz = () |}
This compiles and works as expected and does pretty much what is asked, but without the input argument being generic.
A few things to note:
There is no need to explicitly define the output type.
There is no need for a dynamic type system.
Because the compiler can infer the type definition from the code: an anonymous record with all fields from the input type Foo and the additional Baz field with unit type (this would also work if Foo already had a Baz field in which case it would be replaced).
If we make it generic we get the following compilation error
let addBaz (x: 'a) =
{| x with Baz = () |}
FS3245: The input to a copy-and-update expression that creates an anonymous record must be either an anonymous record or a record
And that makes sense, because there is no way to say that x is a record. We could give it a class or just an int.
So, assuming we could constrain the input to be a record, could this in theory work?
Let's check a few cases by deducing types as the compiler would do for some examples:
type Foo =
{ Foo: int }
type BazInt =
{ Baz: int }
type BazUnit =
{ Baz: unit }
type MoreFields =
{ Bar: string
Foo: int }
let addBaz (x: BazInt) =
{| x with Baz = () |}
let test () =
let foo` = addBaz { Foo = 5 } // OK: addBaz monomorphizes* to `Foo -> {| Baz: unit; Foo: int |}`
let bazInt` = addBaz { BazInt.Baz = 5 } // OK: addBaz monomorphizes* to `BazInt -> {| Baz: unit |}`
let bazUnit` = addBaz { BazUnit.Baz = () } // OK: addBaz monomorphizes* to `BazUnit -> {| Baz: unit |}`
let moreFields` = addBaz { MoreFields.Foo = 1; MoreFields.Bar = "" } // OK: addBaz monomorphizes* to `MoreFields -> {| Bar: string; Baz: unit; Foo: int |}`
*: I used monomorphization because it's the terminology I know from C++ templates, I'm not sure if .net uses the same terminology. But AFAIK, it doesn't matter for this discussion and the idea is the same: you just replace the generic input type 'a with the concrete type used where the function is called.
UPDATE 2:
I now get what Gus points to with the return type. The problem isn't that it can't be deduced as I showed. The problem is that somehow you need to show the generic output type. Something that currently isn't possible in F#. The return type only becomes 'complete' when it the function is called. In C++ this is perfectly fine, but in F# it isn't.

Related

What is missing using interfaces compared to true type-classes?

F# does not (currently) support type-classes. However, F# does support the OOP aspects of C#.
I was wondering, what is lost doing this approach compared to true type-classes?
// A concrete type
type Foo =
{
Foo : int
}
// "Trait" for things that can be shown
type IShowable =
abstract member Show : unit -> string
module Showable =
let show (showable : IShowable) =
showable.Show()
// "Witness" of IShowable for Foo
module Foo =
let asShowable (foo : Foo) =
{
new IShowable with
member this.Show() = string foo.Foo
}
// Slightly awkward usage
{ Foo = 123 }
|> Foo.asShowable
|> Showable.show
|> printfn "%s"
Your suggestion works for simple typeclasses that operate on a single value of a type, like Show. However, what happens when you need a typeclass that isn't so object-oriented? For example, when we want to add two numbers, neither one corresponds to OO's this object:
// not real F#
typeclass Numeric<'a> = // e.g. Numeric<int> or Numeric<float>
abstract member (+) : 'a -> 'a -> 'a // e.g. 2 + 3 = 5 or 2.0 + 3.0 = 5.0
...
Also, keep in mind that many useful typeclasses require higher-kinded types. For example, consider the monad typeclass, which would look something like this:
// not real F#
typeclass Monad<'m<_>> = // e.g. Monad<Option<_>> or Monad<Async<_>>
abstract member Return<'a> : 'a -> 'm<'a>
abstract member Bind<'a, 'b> : 'm<'a> -> ('a -> 'm<'b>) -> 'm<'b>
There's no good way to do this with .NET interfaces.
Higher-kinded type classes are indeed impossible to model with interfaces, but that's just because F# does not support higher-kindedness, not because of type classes themselves.
The deeper thing to note is that your encoding isn't actually correct. Sure, if you just need to call show directly, you can do asShowable like that, but that's just the simplest case. Imagine you needed to pass the value to another function that wanted to show it later? And then imagine it was a list of values, not a single one:
let needsToShow (showable: IShowable) (xs: 'a list) =
xs |> List.iter (fun x -> ??? how do I show `x` ???)
No, this wouldn't do of course. The key is that Show should be a function 'a -> string, not unit -> string. And this means that IShowable itself should be generic:
// Haskell: class Showable a where show :: a -> String
type IShowable<'a> with
abstract member Show : 'a -> string
// Haskell: instance Showable Foo where show (Foo i) = show i
module Foo =
let showable = { new IShowable<Foo> with member _.Show foo = string foo.Foo }
// Haskell: needsToShow :: Show a => [a] -> IO ()
let needsToShow (showable: IShowable<'a>) (xs: 'a list) =
xs |> List.iter (fun x -> printfn "%s" (showable.Show x))
// Haskell: needsToShow [Foo 1, Foo 42]
needsToShow Foo.showable [ { Foo: 1 }; { Foo: 42 } ]
And this is, essentially, what type classes are: they're indeed merely dictionaries of functions that are passed everywhere as extra parameters. Every type has such dictionary either available right away (like Foo above) or constructable from other such dictionaries, e.g.:
type Bar<'a> = Bar of 'a
// Haskell: instance Show a => Show (Bar a) where show (Bar a) = "Bar: " <> show a
module Bar =
let showable (showA: IShowable<'a>) =
{ new IShowable<Bar<'a>> with member _.Show (Bar a) = "Bar: " + showA.Show a }
This is completely equivalent to type classes. And in fact, this is exactly how they're implemented in languages like Haskell or PureScript in the first place: like dictionaries of functions being passed as extra parameters. It's not a coincidence that constraints on function type signatures even kinda look like parameters - just with a fat arrow instead of a thin one.
The only real difference is that in F# you have to do that yourself, while in Haskell the compiler figures out all the instances and passes them for you.
And this difference turns out to be kind of important in practice. I mean, sure, for such a simple example as Show for the immediate parameter, you can just pass the damn instance yourself. And even if it's more complicated, I guess you could suck it up and pass a dozen extra parameters.
But where this gets really inconvenient is operators. Operators are functions too, but with operators there is nowhere to stick an extra parameter (or dozen). Check this out:
x = getY >>= \y -> getZ y <&> \z -> y + 42 > z
Here I used four operators from four different classes:
>>= comes from Monad
<&> from Functor
+ from Num
> from Ord
An equivalent in F# with passing instances manually might look something like:
let x =
bind Foo.monad getY <| fun y ->
map Bar.functor (getZ y) <| fun z ->
gt Int.ord (add Int.num y 42) z
Having to do that everywhere is quite unreasonable, you have to agree.
And this is why many F# operators either use SRTPs (e.g. +) or rely on "known" interfaces (e.g. <) - all so you don't have to pass instances manually.

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

F# Use generic type as pattern discriminator

If there's another way to achieve what I'm trying to do below, please let me know. Suppose I have the following sample code
type FooBar =
| Foo
| Bar
let foobars = [Bar;Foo;Bar]
let isFoo item =
match item with
| Foo _ -> true
| _ -> false
foobars |> Seq.filter isFoo
I want to write a generic/higher-order version of isFoo that allows me to filter my list based on all other types of the discriminated union (Bar in this case).
Something like the following, where 'a can be either Foo or Bar
let is<'a> item =
match item with
| a _ -> true
| _ -> false
However, this attempt yields the following error:
error FS0039: The pattern discriminator 'a' is not defined
If you just want to filter a list, then the easiest option is to use function to write standard pattern matching:
[ Foo; Bar; Foo ]
|> List.filter (function Foo -> true | _ -> false)
If you wanted to write some more complicated generic function that checks for a case and then does something else, then the easiest option (that will work in general) is to take a predicate that returns true or false:
let is cond item =
if cond item then
true
else
false
// You can create a predicate using `function` syntax
is (function Foo -> true | _ -> false) <argument>
In your specific example, you have a discriminated union where none of the cases has any parameters. This is probably an unrealistic simplification, but if you only care about discriminated unions without parameters, then you can just use the cases as values and compare them:
let is case item =
if case = item then
true
else
false
// You can just pass it 'Foo' as the first parameter to
// `is` and use partial function application
[ Foo; Bar; Foo ]
|> List.filter (is Foo)
// In fact, you can use the built-in equality test operator
[ Foo; Bar; Foo ] |> List.filter ((=) Foo)
This last method will not work if you have more complicated discriminated union where some cases have parameters, so it is probably not very useful. For example, if you have a list of option values:
let opts = [ Some(42); None; Some(32) ]
opts |> List.filter (is Some) // ERROR - because here you give 'is' a constructor
// 'Some' instead of a value that can be compared.
You could do various tricks using Reflection (to check for cases with a specified name) and you could also use F# quotations to get a bit nicer and safer syntax, but I do not think that's worth it, because using pattern matching using function gives you quite clear code.
EDIT - Just out of curiosity, a solution that uses reflection (and is slow, not type safe and nobody should actually use it in practice unless you really know what you're doing) could look like this:
open Microsoft.FSharp.Reflection
open Microsoft.FSharp.Quotations
let is (q:Expr) value =
match q with
| Patterns.Lambda(_, Patterns.NewUnionCase(case, _))
| Patterns.NewUnionCase(case, _) ->
let actualCase, _ = FSharpValue.GetUnionFields(value, value.GetType())
actualCase = case
| _ -> failwith "Wrong argument"
It uses quotations to identify the union case, so you can then write something like this:
type Case = Foo of int | Bar of string | Zoo
[ Foo 42; Zoo; Bar "hi"; Foo 32; Zoo ]
|> List.filter (is <# Foo #>)
As long as union cases accept the same set of parameters, you can pass a constructor as an argument and reconstruct DUs for comparison.
It looks more appealing when Foo and Bar have parameters:
type FooBar = Foo of int | Bar of int
let is constr item =
match item with
| Foo x when item = constr x -> true
| Bar x when item = constr x -> true
| _ -> false
In your example, constructors have no argument. So you can write is in a simpler way:
type FooBar = Foo | Bar
let is constr item = item = constr
[Bar; Foo; Bar] |> Seq.filter (is Foo)

How to implement variable arguments in F#

I want to implement a F# function which may accept 1 or 2 arguments. I would like to use the function like this:
let foo = ...
foo "a"
foo "a" "b"
Both the arguments can be the same type. I read the pages about match pattern, active pattern, but cannot find one works for me.
I believe this is due to some of the underlying .Net features, but I think you have to use a class with overloaded methods - something like
type t() =
static member foo a = "one arg"
static member foo (a,b) = "two args"
On a type member, you can use optional params:
type Helper private () =
static member foo (input1, ?input2) =
let input2 = defaultArg input2 "b"
input1, input2
To call this method:
Helper.foo("a")
Helper.foo("a", "b")
Is this what you're after?
You can't use optional params on a function though, unfortunately.
In addition to the other answers, here are a few more "almost solutions". They are not strictly what you wanted, but are worth knowing anyway.
Using a list (or an array) and pattern matching:
let f = function
| [a, b] -> ...
| [a] -> ...
| [] -> failwith "too few arguments"
| _ -> failwith "too many arguments"
f ["a"]
f ["a" ; "b"]
Problems: parameters are not named, not clear from function signature how many parameters it takes.
Using a record to pass all optional parameters:
type FParams = { a : string; b : string }
let fdefault = { a = "a" ; b = "b" }
let f (pars: FParams) = ...
f { fdefault with b = "c" }
Problem: a is also optional, which is not what you wanted. Can be useful though.
In addition to the other answers, you might also be able to do what you want via partial application and currying. Like this:
let foo a b =
a + b
let foo2 a =
foo 1 a;;
Obviously you'd want to fix the first parameter in the call to foo within foo2 to whatever default you want.

Value restriction when there are no generic parameters

I get the value restriction error on let makeElem in the following code:
let elemCreator (doc: XmlDocument) =
fun name (value: obj) ->
let elem = doc.CreateElement(name)
match value with
| :? seq<#XmlNode> as childs ->
childs |> Seq.iter (fun c -> elem.AppendChild(c) |> ignore)
elem
| _ -> elem.Value <- value.ToString(); elem
let doc = new XmlDocument()
let makeElem = elemCreator doc
Why I get the value restriction error if anonymous function returned from elemCreator hasn't any generic parameters?
The compiler states that the infered type of makeElem is (string -> 'a -> XmlNode). But why it infers second parameter as 'a if I've declared it as obj?
I believe that this may be the "expected" behavior (although unfortunate in this case), as a result of the compiler's generalization and condensation processes. Consider Tomas's example:
let foo (s:string) (a:obj) = a
If you were to define
let bar a = foo "test" a
then the compiler will infer the type bar : 'a -> obj because it generalizes the type of the first argument. In your case, you have the equivalent of
let bar = foo "test"
so bar is a value rather than a syntactic function. The compiler does essentially the same inference procedure, except now the value restriction applies. This is unfortunate in your case, since it means that you have to explicitly annotate makeElem with a type annotation (or make it a syntactic function).
This looks like an unexpected behavior to me. It can be demonstrated using a simpler function:
let foo (s:string) (a:obj) = a
let bar = foo "bar" // Value restriction
One possible explanation might be that the F# compiler allows you to call a function taking parameter of some type with an argument of any subtype. So, you can call foo "hi" (new A()) without explicitly casting A to obj (which used to be required some time ago).
This implicit casting could mean that the compiler actually interprets bar as something like this:
let bar a = foo "bar" (a :> obj)
...and so it thinks that the argument is generic. Anyway, this is just a speculation, so you could try sending this as a bug report to fsbugs at microsoft dot com.
(The following is based solely on observation.)
If you have a function obj -> 'a, calls to that function are not used to infer/solve the type of its argument. An illustration:
let writeLine (arg: obj) = System.Console.WriteLine(arg)
writeLine is obj -> unit
let square x =
writeLine x
x * x
In the above function x is inferred as int because of (*). If a type could be constrained by obj then this function would not work (x would be inferred as obj prior to the use of (*), which would cause an error along the lines of: type obj does not support operator (*)).
I think this behavior is a Good Thing. There's no need to restrict a type as obj because every type is already implicitly convertible to obj. This allows your program to be more generic and provides better interoperability with the .NET BCL.
In short, obj has no bearing on type inference (yay!).

Resources