2
votes

I am in the process of learning F# and I am trying to wrap my head around as to why, when I override the inferred type with the correct type, that it infers a different type with List.Filter. Code is worth a thousand words:

type Account = 
{ account : int
  label : string }

type Journal = 
{ account : int
  period : string
  debit : int
  credit : int }

let outputJournal (journals: Journal List) (account:Account) =
    let filtered = List.filter (fun x -> x.account = account.account) journals
    filtered

I need to filter a list of journals against the specified account. However, the outputJournal function outputs an error under the journals argument passed to List.filter. The error is as follows: "Type mismatch. Expecting a 'Account list' but given a 'List Journal'. The type 'Account' does not match the type 'Journal'".

I am confused as to why this is, seeing as I am (or so I thought) clearly trying to filter a list of Journals. Is there a way I can override the type inference to do what I mean or otherwise make my intentions more clear to the compiler (renaming the account field in either record is an option, but I would like to avoid it)?

Much appreciated. Thank you.

1
Type inference is left to right. Annotate the type of x - John Palmer
@JohnPalmer Much appreciated! That'll be extremely helpful to know in the future. - Chris Altig
You can also put journals before List.filter, as in journals |> List.filter (fun ... - Fyodor Soikin

1 Answers

5
votes

Type inference in F# proceeds stricktly top to bottom, left to right.

As a result, when you do x.account the compiler guesses that x is an Account so you get the error message.

To fix this, you can do two things

1) Annotate the type of x

let filtered = List.filter (fun (x:Journal) -> x.account = account.account) journals

2) change the order with a pipe operator (thanks Fyodor)

let filtered = journals |> List.filter (fun x -> x.account = account.account) 

Because of the way type inference works, (2) is more common