himekami
himekami

Reputation: 1459

Confusion on user defined types in f#

For built-in types like int and string, the way to annotate them in a function is like this:

let testFunction (x:int) = x * x

but for user defined types, the way of using them is different. like the one below:

type NewType = NewType of int

let test (NewType a)= a * 2

but if i put it in the following way, the intepreter gives me does not match type error (int vs NewType):

let test (a:NewType) = a * 2

Why is that ?

Upvotes: 2

Views: 258

Answers (2)

mjsottile
mjsottile

Reputation: 191

You are confusing pattern matching with type annotations. Your second example uses a proper type annotation:

let test (a:NewType) = a * 2

Unfortunately, this means that you can't access the int parameter to the type constructor without pattern matching to extract it, like this:

let test (a:NewType) =
    match a with
    | NewType x -> x * 2

The first case that worked for you was not using a type annotation, but was pattern matching as part of the parameter so the value you were trying to access was already given a name and further pattern matching wasn't needed. If your type had more than one pattern possible like this,

type NewType = NewType of int
             | OtherType of float

and you attempted to write the code the first way with a pattern instead of a type annotation, you would see a warning stating that you had an incomplete pattern match:

> let testcode (NewType a) = a * 2;;                  

  let testcode (NewType a) = a * 2;;
  --------------^^^^^^^^^

warning FS0025: Incomplete pattern matches on this expression. For example, 
the value 'OtherType (_)' may indicate a case not covered by the pattern(s).

Upvotes: 2

Tomasz Jaskuλa
Tomasz Jaskuλa

Reputation: 16013

This is a type annotation :

let testFunction (x:int) = x * x

But in the line :

let test (NewType a)= a * 2

this is not a type annotation. It's called decomposition through pattern matching. Pattern matching can be also applied to function parameters like in your example. What it does is unwrapping int value contained in your NewType and binds it to a value. That's why you can do a multiplication because it's done on the int value and not on the NewType

The last line is also a type annotation :

let test (a:NewType) = a * 2

It doesn't work because a multiplication is inferred by default to int and the annotation indicate that a type is of NewType and that's why you get this error message. You have to unwrap it like you do let test (a:NewType) = a * 2

Upvotes: 2

Related Questions