In F#, is there a special name for a type defined in the following manner:
type Foo = int -> string
I ask because such a type seems to have special significance. It is quite abstract compared to other types and seems to only be usable as a sort of function interface. It is not discussed much in F# literature, but it is used quite a bit in the source of many F# OSS projects.
Is it a special sort of type that has some broader significance in functional programming? Does it have other applications other than functioning as a sort of interface for functions? Why is it something that doesn't really make sense to instantiate, even though you can kind of do that by defining a function with a matching type signature? Or is it really just as simple as saying that it is an alias for a function definition which can then be used as a short form in other type signatures/definitions and that accounts for all it's properties?
The name used in the F# documentation for this kind of definition is type abbreviation and I think many people often refer to it as type alias.
The definition defines an alias or a shorter name for a longer type. It says that whenever you type Foo, the compiler will see it as int -> string.
Type abbreviations do not define a new type, which means that Foo and int -> string are equivalent (a value of one type is also a value of the other type). The important points are:
Type inference will generally infer the original type, so when you write a function that matches the type, compiler will infer it as int -> string unless you give an explicit type annotation
When compiled, the abbreviations are erased (because .NET does not have such concept) and so the compiled code will see int -> string.
Abbreviations are useful just for readability reasons - it lets you use more descriptive name for a type. However, they do not have many other implications.
Let me state that I am very green in F# (but 4 years experience in C#). I wanted to start learning F# and I was following the TryFSharp.org tutorials. I came to the point of the computation expressions but things weren't exactly clear. So I started to google it. I came across another tutorial / article which explained it a lot better in the first example (the logging example). But then I read on and came to the second example; I cannot follow the flow of the code or how it is supposed to work, perhaps because I don't understand the definition of the State type:
type State<'a, 's> = State of ('s -> 'a * 's)
I have worked with a few simple types in F# already, I have seen struct, class, record but I have no clue how to read this type or what it is supposed to do. I also can't figure out what the of keyword is doing in there.
So my question is: what does this type definition do / what does the of keyword in it do?
The code defines a discriminated union type named State whose only constructor is also named State and takes an argument of type 's -> 'a * 's. The of keyword separated the constructor name from its argument type.
So basically it says that a State is a function of type 's -> 'a * 's, but you need to use the State constructor to create a State and thus have to write let myState = State someFunction rather than let myState = someFunction.
As already stated, State is a single case discriminated union type. A two-case union type would look like:
type Multi =
| First of name:string
| Second of number:int
One way to think of this is Multi as a base class and First and Second as subclasses where First requires a string in the constructor and Second requires an int. This is a very powerful construct not available in C#. It is powerful because you can pattern match of values of this type and the compiler will force you to handle every case.
A single case union is helpful as a wrapper of another type. In your example, the State type wraps a function from type 's to a pair (C# tuple) 'a * 's. It turns out that this is a very interesting type because it forms a monad and as a result you get all sorts of functions around it. For example, this gist shows how the State monad can be used to implement functional random value generators.
I'm learning F#, when I type any code in Visual Studio and run them on F# Interactive it shows me things like
val foo : x:'a -> 'a
I imagine this mean that foo is a function that receive a paramater x of a type, and returns a value of same x's type.
But What does that ' mean? Many functions show such thing on intellisense too.
The single quote mark (') means that the type of that parameter is generic. It can be inferred, like the example you gave, or it can be explicitly applied.
See here under Implicitly Generic Constructs for more information.
'a represents a type variable, in other words a type that is not determined yet (and doesn't have to be determined yet).
Note that this is different than a', which is a regular variable whose name is two characters: a and '. Contrary to other languages like C#, the single quote is a permitted character in F# variable names, except as the first character in the name to disambiguate from type variables above.
So, if you want to write out a line to the console in F#, you do the following:
System.Console.WriteLine "foo"
Originally I thought the following was pretty much identical, just more verbose, but actually it gives the error "A unique overload for method 'WriteLine' could not be determined based on type information prior to this program point":
(fun line -> System.Console.WriteLine line) "foo"
It seems the second version is confused by the presence of overloaded WriteLine methods that take a string as well as other arguments. Is my assumption along the right lines?
Not exactly. In the first case, the function call knows that it's being applied to a string literal, so it can do overload resolution to find the string overload.
In the second case, line is an unsolved type variable to type inference at the point of the call to the overloaded WriteLine method, so it doesn't know which overload to pick, and it hasn't seen the string argument yet, as type inference is left-to-right.
Change it to
"foo" |> (fun line -> System.Console.WriteLine line)
and it will work, because the type inference variable for line will get unified with string from "foo" coming in, before it needs to determine the WriteLine call.
So they key is left-to-right type inference; in the absence of a solution to a type variable, it may not be possible to pick an overload yet.
I'm reading Real World Haskell Pg 151, and I've stared at the following passage for over an hour:
Recall that String is a synonym for
[Char], which in turn is the type [a]
where Char is substituted for the type
parameter a. According to Haskell 98's
rules, we are not allowed to supply a
type in place of a type parameter when
we write an instance. In other words,
it would be legal for us to write an
instance for [a], but not for [Char].
16 comments 5335
It simply isn't sinking in. Staring at the the (free not pirated) copy of RWH chapter 6 I see a lot of other people are really suffering with this. I still don't understand it from the comments...
Firstly, everything about this confuses me, so please if you feel you can explain anything about this passage, or TypeSynonymInstances please do.
Here is my problem:
Int is a data constructor
String is a data constructor AND type synonym
Now I can't answer these questions:
Why would a type synonym preclude the making the type a member of a type class (I'm looking for some reason which probably relates to compilation or implimentation of a type synonym)?
Why did the designers of the language, not want this syntax (I'm asking for reasoning not extensive theory or unicode math symbols).
I see this line "the type [a] where Char is substituted for the type parameter a", and I want to know why I can't substitute it for this "the type a where Int is substituted for the type parameter a".
Thanks!
I think part of the issue is that two, largely unrelated, restrictions are in play:
No type synonym instances means that instances can only be things declared with data or newtype, not type. This forbids String, but not [Char].
No flexible instances means that instances can only mention one type that isn't a variable, and only that type can be used as a type constructor. This forbids Maybe Int and f Int, but not Maybe a.
Here's what GHCi says about Int, Char, and String:
data Char = GHC.Types.C# GHC.Prim.Char#
data Int = GHC.Types.I# GHC.Prim.Int#
type String = [Char]
Int and Char are both simple types without type variable parameters; there's no type constructor involved, so you can make instances with them pretty much freely.
String, however, fails on both counts. It's a type synonym, which isn't allowed, and it's also a type constructor applied to a non-variable, namely the list type constructor applied to Char.
For comparison, note that [a], Maybe a, and Either a b are all valid in instances, but [Int], Maybe [a], and Either String a are forbidden; hopefully you can now see why.
As for your direct questions, I don't know what the original motivations were for designing the language that way, and I'm in no way qualified to make authoritative statements about "best practices", but for my own personal coding I don't really hesitate to use these pragmas:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
You could always go look at packages that use pragmas. Flexible instances, it seems, do get a fair amount of use, and from "respectable" packages (there's a couple hits in the source for Parsec, for instance).
Actually, neither Int nor String are data constructors. That is, you can't use them to create a value of
> (Int 42, String "bob")
<interactive>:1:1: Not in scope: data constructor `Int'
<interactive>:1:9: Not in scope: data constructor `String'
Int names a new, distinct, algebraic data type. String is a "type-synonym", or alias, for the already existing type: [Char]. The problem is that Haskell 98 says you can't use a type synonym in an instance declaration.
I can't say why authors of the Haskell 98 report choose to restrict type synonyms in this case. There are quite a number of restrictions on them. For example, they cannot be partially applied (if they take type arguments). I think a clue comes at the end of ยง4.2.2:
Type synonyms are a convenient, but
strictly syntactic, mechanism to make
type signatures more readable. A
synonym and its definition are
completely interchangeable, except in
the instance type of an instance
declaration (Section 4.3.2).
Presumably, there was an approach to program compilation, for which this syntactic interchangeability would have caused problems for instances. Perhaps it has to do with notable aspect of instances that they leak out of packages...
As to your last question, I believe that explanation is conflating two things: 1) String is a type synonym for [Char], which is in turn a specialization of the more general type [a] and 2) that even without the synonym, [Char] cannot be used in the head of an instance.
This second problem has nothing to do with type synonyms, but that instance heads must have all the type parameters to the type constructor be variables, not concrete types. That is, you can't define separate instances for [Int] and [Char] for some class, you can only defined an instances [a]. (Remember, that despite the convenient syntax, [] is a type constructor, and the thing inside is the type parameter.)
Again, I don't know why the report restricts these, but I suspect it also has to do with compilation strategy. Since GHC's compilation strategy for instances can handle this, you can relax this constraint in GHC via -XFlexibleInstances.
Finally, I've seen both extensions turned on in quite a lot of code, but perhaps someone with more Haskell experience can weigh in as to if they are "best practices" or no.
Haskell 98
an instance head must have the form C (T u1 ... uk), where T is a type constructor defined by a data or newtype declaration (see TypeSynonymInstances) and the ui are distinct type variables, and
each assertion in the context must have the form C' v, where v is one of the ui.
So it is valid to use instance ClassName TypeConstructor where and TypeConstructor MUST be such as Int, Double or [a], make sure that only can a type constructor be involved!!
BTW, [] is type constructor, so [TypeConstructor] cannot be used but [NewType] and [TypeVariable] are allowed.
This is a restriction is Haskell, and we can avoid it by enabling FlexibleInstances.
Int and String are types, not data construtors. String happens to be an alias for [Char] which can also be written List Char. A data constructor is something like Just, so Just 3 is a value of type Maybe Int. Type synonym instances are explained here:
http://hackage.haskell.org/trac/haskell-prime/wiki/TypeSynonymInstances