With these two Discriminated Unions (DUs) :
type Premier = |M1 of int
type Second = |M2 of Premier
I can have these valid lines of code :
let p_1 = M1 42
let p_2 = 42 |> M1
let p_3 = Premier.M1 42
let s_1 = M2 (M1 42)
let s_2 = 42 |> M1 |> M2
But the following nested dot syntax is not accepted (important difference with classes syntax) :
let s_3 = Second.M2.M1 42
Question : What is the fundamental reason it is so ? I mean are there conflicts or inconsistencies with other parts of F# syntax / grammar that prevent it ? Or does it result in type inference difficulties ?
Follow-up : I still have 2 ways (s_1 and s_2) to define my variable of type Second but is there a more idiomatic and concise third way for DUs ?
I do not see why this should work. The two ways that work are the standard ways for creating a discriminated union that contains another value. The third option that you're trying does not make sense from the F# perspective. To explain a bit more:
M1 42 is a value of type Premier
M2 is a constructor that takes Premier and returns Second
M2 (M1 42) calls the constructor with an argument - and so you get Second
With piping, the thing works exactly the same
42 |> M1 passes the int to the constructor M1 resulting in Premier value
42 |> M1 |> M2 means (42 |> M1) |> M2 - that is, it passes Premier value to the M2 constructor and you get `Second.
As for your attempt to write Second.M2.M1 42, this is not valid because:
Second.M2 is a constructor (a function) that expects Premier and returns Second.
A function does not have any members - so you cannod do . on a constructor.
Related
I had expected that flexible type would minimize the need of explicit upcast, but
type IB =
abstract B : int
type A() =
interface IB with
member this.B = 1
let a = A()
let test (x) = x
let aa = [|a; a|]
let case1 = aa |> Array.map (fun (x: #IB) -> test (x.B))
let case2 = Array.map (fun (x: #IB) -> test (x.B)) aa
Here, there are warnings (less generic than type annotation) on the last 2 lines. The compiler is able to compile case2, but fails at case1, why is that?
It feels odd that the more detailed the compiler can infer, the more code I need to write.
#kvb pointed out there is a simple fix, just to refactor the lambda function into a non inline version.
let fix (x: #IB) =
test x.B
let case1 = aa |> Array.map fix
let case2 = Array.map fix
This works well.
Type inference in F# flows from left to right, so it's not too surprising that piping can break or fix things. However, it's almost always the case that having more type information earlier is helpful, so this result is a bit surprising. The warnings are a subtle indicator that you're doing something wrong. Flexible types seem like they ought to be applicable in many tricky situations, but there are really only a few places where they help. Array.map takes a function of some type 'a -> 'b for some particular 'a and 'b (though there's a little bit of nuance here, since the "particular" types could be type variables), so having a "more generic" argument like #IB -> int is not especially helpful; the compiler will pick some particular subtype of IB during compilation - this is what the warnings are attempting to communicate.
As I said, the different results you see on the different lines are due to the fact that type inference in F# works left to right. In the first case, the information about the type of aa flows into the type checking of the remainder of the expression and so when compiling the lambda the compiler knows that the only possible subtype of IB that will work is A, but because interface implementations are always implicit this causes a compile time error because A doesn't have a publicly available member B. On the other hand, in the second case, when the compiler's trying to check Array.map it doesn't yet know the type of the array it will be applied to, but can check the call in any case because regardless of the subtype it will support the interface method IB.B (implicitly upcasting the argument from whatever subtype of IB it has to just IB). Then when this is applied to aa the compiler specializes the implementation to A, but because of the implicit upcast this still works okay. Intuitively, it seems like the compiler ought to have been able to have inserted the same implicit upcast in the former case, but I think this is probably just a surprising result of the inference algorithm and not an actual bug.
Perhaps more surprising, one possible fix is to just use a let-bound definition (for either the lambda or even as a type-restricted version of Array.map) and skip the flexible type:
let f (x:IB) = test (x.B)
let g (f:IB -> int) = Array.map f
let d' = aa |> g (fun x -> test (x.B))
let d'' = aa |> Array.map f
let c' = g (fun x -> test (x.B)) aa
let c'' = Array.map f aa
So what's happening here? It turns out the compiler does something called "Implicit Insertion of Flexibility for Uses of Functions and Members" (section 14.4.3 of the spec for F# 3.1) which does exactly what you want.
type IB =
abstract B : int
type A() =
interface IB with
member this.B = 1
let a = A()
let test (x) = x
let aa = [|a; a|]
Here the compiler knows that aa is an array of A so type annotation in lambda is not needed but you have to cast x to the interface type because in F# interfaces are implemented explicitely (http://msdn.microsoft.com/en-us/library/ms173157.aspx):
let d = aa |> Array.map (fun x -> test ((x:>IB).B))
Here the compiler at the moment of compiling lambda doesn't know what a type of x is, so you need a type annotation telling that x is implementation of IB interface so you can refer to x.B property directly:
let c = Array.map (fun (x: #IB) -> test (x.B)) aa
Put an F# infix operator in brackets, and it behaves like a function,
let foo = (*) 3 2 // foo = 6
let factorial n = [2..n] |> List.fold (*) 1 // n!
However, this doesn't work with the :: operator (cons operator),
let ls = (::) 1 [2..5] // Error: Unexpected symbol '::' in binding.
What's the reason for this?
You can use the static method:
let ls = List.Cons (1, [2..5])
or the operator's verbose name:
let ls = op_ColonColon (1, [2..5])
(checked with F# 3.0; older versions may behave differently. For instance, MSDN suggests op_Cons)
In both cases, there's no way to curry the arguments here. Numeric operators are defined like this:
let inline ( * ) (x:int) (y:int) = ...
The list concatenation, however, requires a tuple, and this also answers your question,
What's the reason for this?
In fact, (::) is not an usual operator (a standalone function or a type member), but a union case. Here's how the List<'T> is defined in F# sources:
type List<'T> =
| ([]) : 'T list
| (::) : Head: 'T * Tail: 'T list -> 'T list
So, if your purpose is partial application of arguments, the only nice solution would be writing a wrapper function as #pad has suggested.
Because (::) (and [] for that matter) is a symbolic keyword, you can't expect to use it as an infix operator. See F# specification, section 3.6 Symbolic keywords.
In this case, you have to define an extra function e.g.
let cons x xs = x :: xs
let ls = cons 1 [2..5]
For starters, I'm a novice in functional programming and F#, therefore I don't know if it's possible to do such thing at all. So let's say we have this function:
let sum x y z = x + y + z
And for some reason, we want to invoke it using the elements from a list as an arguments. My first attempt was just to do it like this:
//Seq.fold (fun f arg -> f arg) sum [1;2;3]
let rec apply f args =
match args with
| h::hs -> apply (f h) hs
| [] -> f
...which doesn't compile. It seems impossible to determine type of the f with a static type system. There's identical question for Haskell and the only solution uses Data.Dynamic to outfox the type system. I think the closest analog to it in F# is Dynamitey, but I'm not sure if it fits. This code
let dynsum = Dynamitey.Dynamic.Curry(sum, System.Nullable<int>(3))
produces dynsum variable of type obj, and objects of this type cannot be invoked, furthermore sum is not a .NET Delegate.So the question is, how can this be done with/without that library in F#?
F# is a statically typed functional language and so the programming patterns that you use with F# are quite different than those that you'd use in LISP (and actually, they are also different from those you'd use in Haskell). So, working with functions in the way you suggested is not something that you'd do in normal F# programming.
If you had some scenario in mind for this function, then perhaps try asking about the original problem and someone will help you find an idiomatic F# approach!
That said, even though this is not recommended, you can implement the apply function using the powerful .NET reflection capabilities. This is slow and unsafe, but if is occasionally useful.
open Microsoft.FSharp.Reflection
let rec apply (f:obj) (args:obj list) =
let invokeFunc =
f.GetType().GetMethods()
|> Seq.find (fun m ->
m.Name = "Invoke" &&
m.GetParameters().Length = args.Length)
invokeFunc.Invoke(f, Array.ofSeq args)
The code looks at the runtime type of the function, finds Invoke method and calls it.
let sum x y z = x + y + z
let res = apply sum [1;2;3]
let resNum = int res
At the end, you need to convert the result to an int because this is not statically known.
My problem, in a nutshell, is this:
What can I do about storing a tuple (or any type with a constraint of 'comparison') in a C# container that requires an IComparable?
This works:
> let x (y : 'a when 'a : comparison) = y ;;
val x : y:'a -> 'a when 'a : comparison
> x (1,2) ;;
val it : int * int = (1, 2)
I would have thought this would work:
> let x (y : IComparable<int>) = y ;;
val x : y:IComparable<int> -> IComparable<int>
> x (1,2) ;;
x (1,2) ;;
---^^^
stdin(28,4): error FS0001: The type ''a * 'b' is not compatible with the type 'IComparable<int>'
And this as well:
> let x (y : IComparable) = y ;;
val x : y:IComparable -> IComparable
> x (1,2) ;;
x (1,2) ;;
---^^^
stdin(30,4): error FS0001: The type ''a * 'b' is not compatible with the type 'IComparable'
EDIT
I follow the argument that F# doesn't do implicit upcasting. However, even explicitly:
> (1, 2) :> IComparable ;;
(1, 2) :> IComparable ;;
^^^^^^^^^^^^^^^^^^^^^
stdin(43,1): error FS0193: Type constraint mismatch. The type
int * int
is not compatible with type
IComparable
The type 'int * int' is not compatible with the type 'IComparable'
I suppose this makes sense as the comparability of a F# tuple is inferred structurally within the F# type system, and perhaps that extra information is not available to .NET.
It seems one workaround per a comment below is invoking
Tuple<_,_> (1,2) ;;
Or even
box (1, 2) :?> IComparable ;;
F# does not do implicit upcasting as C# does. If you request an IComparable, then you are requesting an IComparable and not something which can be upcast to IComparable
What you really want, is requesting a type, that happens to implement IComparable, but you are still working with the specific type.
That's why let x (y : 'a when 'a : comparison), see that y is of type 'a, whereas 'a can be statically upcast to comparison (if you want to access a member of comparison, you will have to upcast to comparison using :> first)
On the other hand let x (y : IComparable<int>) = y requests very explicitly a IComparable<int>. But you are passing (1,2), a value, that can be upcast to IComparable. So if you pass (1,2) :> IComparable<int> or even (1,2) :> _, the compiler will be able to pass the value. You can wrap up the comparable, but you lose type information, the return value will be a IComparable and no longer an int*int.
let wrapComparable value =
{
new IComparable with
member this.CompareTo other =
match other with
| :? 'a as other -> compare value other
| _ -> raise <| InvalidOperationException()
}
Also, here you need to consider, that IComparable is based on obj so you probably need to consider the case, where your other is of a different type.
In case, you only need IComparable<'a> the code becomes simpler:
let wrapComparable value =
{
new IComparable<_> with
member this.CompareTo other = compare value other
}
As such, as a rule of thumb, you usually want to make a generic function with type constraints, rather than requesting an interface, as you would in C#. This is due to the fact, that F# does not do automatic upcasting.
A very detailed explanation about equality and comparisons can be found in http://lorgonblog.wordpress.com/2009/11/08/motivating-f-equality-and-comparison-constraints/ and http://blogs.msdn.com/b/dsyme/archive/2009/11/08/equality-and-comparison-constraints-in-f-1-9-7.aspx. Also the MSDN states, that
If you are only using tuples from F# and not exposing them to other languages, and if you are not targeting a version of the .NET Framework that preceded version 4, you can ignore this section.
Tuples are compiled into objects of one of several generic types, all named Tuple, that are overloaded on the arity, or number of type parameters. Tuple types appear in this form when you view them from another language, such as C# or Visual Basic, or when you are using a tool that is not aware of F# constructs. The Tuple types were introduced in .NET Framework 4. If you are targeting an earlier version of the .NET Framework, the compiler uses versions of System.Tuple from the 2.0 version of the F# Core Library. The types in this library are used only for applications that target the 2.0, 3.0, and 3.5 versions of the .NET Framework. Type forwarding is used to ensure binary compatibility between .NET Framework 2.0 and .NET Framework 4 F# components.
So it seems, that the fact, that Tuples, happen to be System.Tuple is really just an implementation detail at which point, the lack of IComparison makes somewhat sense.
Definitely some weirdness going on. FWIW, it works if you construct a System.Tuple<_, _> explicitly, so that might be a workaround:
let x (y : IComparable) = y
let t = (2, 3)
x (Tuple<_,_> t)
A real F# noob question, but what is |> called and what does it do?
It's called the forward pipe operator. It pipes the result of one function to another.
The Forward pipe operator is simply defined as:
let (|>) x f = f x
And has a type signature:
'a -> ('a -> 'b) -> 'b
Which resolves to: given a generic type 'a, and a function which takes an 'a and returns a 'b, then return the application of the function on the input.
You can read more detail about how it works in an article here.
I usually refer to |> as the pipelining operator, but I'm not sure whether the official name is pipe operator or pipelining operator (though it probably doesn't really matter as the names are similar enough to avoid confusion :-)).
#LBushkin already gave a great answer, so I'll just add a couple of observations that may be also interesting. Obviously, the pipelining operator got it's name because it can be used for creating a pipeline that processes some data in several steps. The typical use is when working with lists:
[0 .. 10]
|> List.filter (fun n -> n % 3 = 0) // Get numbers divisible by three
|> List.map (fun n -> n * n) // Calculate squared of such numbers
This gives the result [0; 9; 36; 81]. Also, the operator is left-associative which means that the expression input |> f |> g is interpreted as (input |> f) |> g, which makes it possible to sequence multiple operations using |>.
Finally, I find it quite interesting that pipelining operaor in many cases corresponds to method chaining from object-oriented langauges. For example, the previous list processing example would look like this in C#:
Enumerable.Range(0, 10)
.Where(n => n % 3 == 0) // Get numbers divisible by three
.Select(n => n * n) // Calculate squared of such numbers
This may give you some idea about when the operator can be used if you're comming fromt the object-oriented background (although it is used in many other situations in F#).
As far as F# itself is concerned, the name is op_PipeRight (although no human would call it that). I pronounce it "pipe", like the unix shell pipe.
The spec is useful for figuring out these kinds of things. Section 4.1 has the operator names.
http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html
Don't forget to check out the library reference docs:
http://msdn.microsoft.com/en-us/library/ee353754(v=VS.100).aspx
which list the operators.