I'm trying to understand functional programming using F# and to do so I started small project, but I run in following issue and can't seem to find any elegant solution for it.
I created Validation<'a> which is pretty much specialized F# Result: Result<'a, Error list> which helps me to handle validation results.
I have two functions that perform some validation both with signatures:
'a -> Validation<'b>
There is also a third function that consumes validated arguments with signature:
'a -> 'b -> Validation<'c>
What I would like to achieve is to:
Validate argument 'a
If validation of argument 'a passes, validate argument 'b
If validation of argument 'b passes, provide arguments 'a and 'b to final function
Thus far I used apply function to achieve such behaviour, but when I try to use it in this case the result type is nested Validation Validation<Validation<'c>>, since final function itself returns Validation. I would like to get rid of one of validations, so that result type would be Validation<'c>. I tried to experiment with bind and variants of lift functions which I found here, but result remains the same. Is nested match an only option here?
Edit #1: Here is a simplified code that I currently have:
Here are types that handle validation:
[<Struct>]
type Error = {
Message: string
Code: int
}
type Validation<'a> =
| Success of 'a
| Failure of Error list
let apply elevatedFunction elevatedValue =
match elevatedFunction, elevatedValue with
| Success func, Success value -> Success (func value)
| Success _, Failure errors -> Failure errors
| Failure errors, Success _ -> Failure errors
| Failure currentErrors, Failure newErrors -> Failure (currentErrors#newErrors)
let (<*>) = apply
Problematic function is this one:
let formatReport (unvalidatedLanguageName: string) (unvalidatedReport: UnvalidatedReport): Validation<Validation<string>> =
Success formatReportAsText
<*> languageTranslatorFor unvalidatedLanguageName
<*> reportFrom unvalidatedReport
Validation functions:
let languageTranslatorFor (unvalidatedLanguageName: string): Validation<Entry -> string> = ...
let reportFrom (unvalidatedReport: UnvalidatedReport): Validation<Report> = ...
Function that consumes validation arguments:
let formatReportAsText (languageTranslator: Entry -> string) (report: Report): Validation<string> = ...
Edit #2: I attempted to use solution provided by #brianberns and implemented computation expression for Validation<'a> type:
// Validation<'a> -> Validation<'b> -> Validation<'a * 'b>
let zip firstValidation secondValidation =
match firstValidation, secondValidation with
| Success firstValue, Success secondValue -> Success(firstValue, secondValue)
| Failure errors, Success _ -> Failure errors
| Success _, Failure errors -> Failure errors
| Failure firstErrors, Failure secondErrors -> Failure (firstErrors # secondErrors)
// Validation<'a> -> ('a -> 'b) -> Validation<'b>
let map elevatedValue func =
match elevatedValue with
| Success value -> Success(func value)
| Failure validationErrors -> Failure validationErrors
type MergeValidationBuilder() =
member _.BindReturn(validation: Validation<'a>, func) = Validation.map validation func
member _.MergeSources(validation1, validation2) = Validation.zip validation1 validation2
let validate = MergeValidationBuilder()
and use it as such:
let formatReport (unvalidatedLanguageName: string) (unvalidatedReport: UnvalidatedReport): Validation<Validation<string>> =
validate = {
let! translator = languageTranslatorFor unvalidatedLanguageName
and! report = reportFrom unvalidatedReport
return formatReportAsText translator report
}
While computation expression is definitely nicer to read the end result remains exactly the same [Validation<Validation>] due to fact that "formatReportAsText" function also returns result wrapped in Validation.
To somewhat merge stacked validations I used below function, but it seems clunky to me:
// Validation<Validation<'a>> -> Validation<'a>
let merge (nestedValidation: Validation<Validation<'a>>): Validation<'a> =
match nestedValidation with
| Success innerValidation ->
match innerValidation with
| Success value -> Success value
| Failure innerErrors -> Failure innerErrors
| Failure outerErrors -> Failure outerErrors
Edit #3: After addition of "ReturnFrom" function to validation computation expression to flatten nested validations the validation function works as intended.
member _.ReturnFrom(validation) = validation
The final version of validation function that uses computation expression is:
let formatReport (unvalidatedLanguageName: string) (unvalidatedReport: UnvalidatedReport): Validation<string> =
validate = {
let! translator = languageTranslatorFor unvalidatedLanguageName
and! report = reportFrom unvalidatedReport
return! formatReportAsText translator report
}
There are lots of ways to skin that cat, but central to most of them is that whenever you encounter a nested container like Validation<Validation<string>>, you'll need some way to 'flatten' the nesting. For a type like Validation, that's easy:
// Validation<Validation<'a>> -> Validation<'a>
let join = function
| Success x -> x
| Failure errors -> Failure errors
You might also choose to call this function flatten, but it's often called join.
You may also find a map function useful. This one is also easy:
// ('a -> 'b) -> Validation<'a> -> Validation<'b>
let map f = function
| Success x -> Success (f x)
| Failure errors -> Failure errors
Such a map function makes Validation a functor.
When you have both map and join, you can always implement a method usually known as bind:
// ('a -> Validation<'b>) -> Validation<'a> -> Validation<'b>
let bind f = map f >> join
The ability to flatten or join a nested container is what makes it a monad. While it's a word surrounded by mystique and awe, it's really just that: it's a functor you can flatten.
Usually, however, join and bind are defined the other way around:
let bind f = function
| Success x -> f x
| Failure errors -> Failure errors
let join x = bind id x
With join you can adjust the problematic function by flattening the nested container:
// string -> UnvalidatedReport -> Validation<string>
let formatReport (unvalidatedLanguageName: string) (unvalidatedReport: UnvalidatedReport) =
Success formatReportAsText
<*> languageTranslatorFor unvalidatedLanguageName
<*> reportFrom unvalidatedReport
|> join
That's not how I'd do it, however. While such combinator gymnastics can be fun, they' aren't always the most readable solution.
Computation expression
I'd prefer defining a Computation Expression, which can minimally be done like this:
type ValidationBuilder () =
member _.Bind (x, f) = bind f x
member _.ReturnFrom x = x
let validate = ValidationBuilder ()
This now enables you to write the desired function like this:
// string -> UnvalidatedReport -> Validation<string>
let formatReport (unvalidatedLanguageName: string) (unvalidatedReport: UnvalidatedReport) =
validate {
let! l = languageTranslatorFor unvalidatedLanguageName
let! r = reportFrom unvalidatedReport
return! formatReportAsText l r
}
The problem with this version, however, is that it doesn't use the apply function to append to errors together. In other words, it'll short-circuit on the first error it encounters.
In order to support collecting errors without short-circuiting, you're going to need a computation builder that supports applicative functors, like #brianberns pointed to. You can also see an example here.
Since formatReportAsText returns a validated string (rather than a plain string), you should use return! instead of return at the end of your computation expression:
return! formatReportAsText translator report
This is equivalent to:
let! value = formatReportAsText translator report // value is a string
return value
If I understand your code correctly, the type of the computation expression will then be Validation<string> instead of Validation<Validation<string>>.
Note that you'll need a ReturnFrom method on your builder to make return! work:
member __.ReturnFrom(value) = value
See this page for details.
First of all, I think you are getting into a fairly advanced area of F# - but the most practical solution would be to use a computation builder as referenced in the previous answer linked by #brianberns in the comment.
If you wanted to stick to the somewhat simpler approach based on combinators, you could do this using the following functions:
val merge : Validation<'a> -> Validation<'b> -> Validation<'a * 'b>
val bind : ('a -> Validation<'b>) -> Validation<'a> -> Validation<'b>
Merge is a function that takes two possibly validated values and produces a new one that combines the errors (as your original apply function). The Bind function applies a function to a validated value and collapses the "nested" validation in the result. They can be implemented as:
let merge elevatedValue1 elevatedValue2 =
match elevatedValue1, elevatedValue2 with
| Success v1, Success v2 -> Success (v1, v2)
| Success _, Failure errors -> Failure errors
| Failure errors, Success _ -> Failure errors
| Failure e1, Failure e2 -> Failure (e1 # e2)
let bind f elevatedValue =
match elevatedValue with
| Success value ->
match f value with
| Success value -> Success value
| Failure e -> Failure e
| Failure e -> Failure e
Thanks to merge, you can validate the two inputs and (possibly) merge the errors. Thanks to bind, you can then continue the computation and handle the fact that the rest of it may also fail. You can write your composed function as:
let formatReport (unvalidatedLanguageName: string)
(unvalidatedReport: UnvalidatedReport): Validation<string> =
merge
(languageTranslatorFor unvalidatedLanguageName)
(reportFrom unvalidatedReport)
|> bind formatReportAsText
Related
The following code is extracted from an application and adapted to highlight the issue as easy as possible
module Mo
open System
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.RuntimeHelpers
open System.Linq.Expressions
type Type() =
member _.Prop1 with get() = 1
member _.Prop2 with get() = 2
let toFunc<'t when 't :> Type>(filter: 't -> Expr<bool>) =
let xp = <# Func<'t, bool>(fun (t: 't) -> %(filter t) && t.Prop2 = 2) #>
LeafExpressionConverter.QuotationToExpression xp |> unbox<Expression<Func<'t, bool>>>
let getFunc (i: int) =
let filter (t: Type) = <# t.Prop1 = i #>
toFunc filter
the problem is in the line
let xp = <# Func< 't, bool>(fun (t: 't) -> %(filter t) && t.Prop2 = 2) #>
The compiler complains in fun (t: 't) as follows:
Error FS0446
The variable 't' is bound in a quotation but is used as part of a spliced expression.
This is not permitted since it may escape its scope.
The intent is to compose quotations into a filter Linq expression.
Is there a (alternative) way to do this?
EDIT:
Some more context looks necessary:
The returned Func expression is later passed to Azure.Data.Tables.TableClient.Query(). Unfortunately this method doesn't support expressions containing function calls.
Converting filter to a quoted function (as suggested by Fyodor) was my first version, but I had to abandon it because of this requirement of the Azure Tables SDK.
So the question becomes :
Is it possible to achieve the result of an expression that doesn't contain calls to external method/function?
You're mixing up your variables between quotation realm and "regular" realm.
filter is not a quoted function. It's a regular function that returns a quotation. Regular functions get regular parameters, quoted functions get quoted parameters.
The t parameter here:
let xp = <# Func<'t, bool>(fun (t: 't) -> %(filter t) && t.Prop2 = 2) #>
^
|
This one
That's a quoted parameter. It's defined inside a quotation.
And yet, you're trying to pass its value to the filter function. But at the moment of constructing the quotation, the parameter t doesn't have a value yet! Only when you're done constructing the quotation, then compile it to IL, and then call it, - only then will the parameter t have a value, allowing you to call the filter function. But you need the result of filter function to finish constructing the quotation in the first place!
The most straightforward fix is to make filter a quoted function. Then you can splice it into the quotation, and then pass the parameter t to the result of splicing:
let toFunc<'t when 't :> Type>(filter: Expr<'t -> bool>) =
let xp = <# Func<'t, bool>(fun (t: 't) -> (%filter) t && t.Prop2 = 2) #>
LeafExpressionConverter.QuotationToExpression xp |> unbox<Expression<Func<'t, bool>>>
let getFunc (i: int) =
let filter = <# fun (t: Type) -> t.Prop1 = i #>
toFunc filter
I've created a type for lazy binary tree:
type 'a lBT = LEmpty | LNode of 'a * (unit -> 'a lBT) * (unit -> 'a lBT);;
and wanted to create an instance of it:
let exlBST = LNode(3, function() -> LEmpty, function() -> LEmpty);;
but I received this error:
Error: The constructor LNode expects 3 argument(s),
but is applied here to 2 argument(s)
Can you tell me what's going on? Isn't unit considered as an argument?
The argument to LNode is not parsed as you expect, a triple with two functions, but as a pair where the the second item is a function returning another pair. Use parentheses around at least the middle function, but preferably both for consistency, to make your intention explicit:
let exlBST = LNode (3, (function () -> LEmpty), (function () -> LEmpty));;
There are unfortunately a few of these weird parsing edge cases/ambiguities with OCaml's syntax. You'll learn to deal with it in time, but a good rule of thumb is: If in doubt, use parentheses (or begin/end when appropriate)
I'm learning F#. I want to know best practices for validating input parameters. In my naivety I had thought I could do something like this:
let foo = match bar with
| <test for valid> -> bar
| _ -> "invalid"
of course that doesn't work due to mismatching types. So I'd like to see the patterns experienced F# programmers use for this sort of thing. match? If/then/else?
Something else?
You are having problems because you are trying to bind a value to something that could be two possible types depending upon program flow - that is incompatible with static typing.
If I have some value foo, it cannot be, for example, a string OR an int depending upon program flow; it must resolve to exactly one type at compile time.
You can, however, use a discriminated union that can represent several different options within a single type.
Here is a summary of the approaches for doing just that.
Result Type / Either
F# 4.1, which is currently available via nuget, introduces the Result type. You may find this type referred to as Either in other languages.
It is defined like this:
[<Struct>]
type Result<'T,'TError> =
/// Represents an OK or a Successful result. The code succeeded with a value of 'T.
| Ok of ResultValue:'T
/// Represents an Error or a Failure. The code failed with a value of 'TError representing what went wrong.
| Error of ErrorValue:'TError
If you are pre-F# 4.1 (which is very likely). You can define this type yourself, although you must remove the [<Struct>] attribute.
You can then make a tryParseFloat function:
let tryParseFloat str =
match System.Double.TryParse str with
| true, f -> Ok f
| _ -> Error <| sprintf "Supplied string (%s) is not a valid float" str
You can determine success or failure:
match tryParseFloat "0.0001" with
|Ok v -> // handle success
|Error err -> // handle error
In my opinion, this is the preferred option, especially in F# 4.1+ where the type is built in. This is because it allows you to include information relating to how and why some activity failed.
Option Type / Maybe
The option type contains either Some 'T or simply None. The option type is used to indicate the presence or absence of a value, None fills a role similar to null in other languages, albeit far more safely.
You may find this type referred to as Maybe in other languages.
let tryParseFloat str =
match System.Double.TryParse str with
| true, f -> Some f
| _ -> None
You can determine success or failure:
match tryParseFloat "0.0001" with
|Some value -> // handle success
|None -> // handle error
Composition
In both cases, you can readily compose options or results using the associated map and bind functions in the Option and Result modules respectively:
Map:
val map: mapping:('T -> 'U) -> option:'T option -> 'U option
val map : mapping:('T -> 'U) -> result:Result<'T, 'TError> -> Result<'U, 'TError>
The map function lets you take an ordinary function from 'a -> 'b and makes it operate on results or options.
Use case: combine a result with a function that will always succeed and return a new result.
tryParseFloat "0.001" |> Result.map (fun x -> x + 1.0);;
val it : Result<float,string> = Ok 1.001
Bind:
val bind: binder:('T -> 'U option) -> option:'T option -> 'U option
val bind: binder:('T -> Result<'U, 'TError>) -> result:Result<'T, 'TError> -> Result<'U, 'TError>
The bind function lets you combine results or options with a function that takes an input and generates a result or option
Use case: combine a result with another function that may succeed or fail and return a new result.
Example:
let trySqrt x =
if x < 0.0 then Error "sqrt of negative number is imaginary"
else Ok (sqrt x)
tryParseFloat "0.001" |> Result.bind (fun x -> trySqrt x);;
val it : Result<float,string> = Ok 0.0316227766
tryParseFloat "-10.0" |> Result.bind (fun x -> trySqrt x);;
val it : Result<float,string> = Error "sqrt of negative number is imaginary"
tryParseFloat "Picard's Flute" |> Result.bind (fun x -> trySqrt x);;
val it : Result<float,string> =
Error "Supplied string (Picard's Flute) is not a valid float"
Notice that in both cases, we return a single result or option despite chaining multiple actions - that means that by following these patterns you need only check the result once, after all of your validation is complete.
This avoids a potential readability nightmare of nested if statements or match statements.
A good place to read more about this is the Railway Oriented Programming article that was mentioned to you previously.
Exceptions
Finally, you have the option of throwing exceptions as a way of preventing some value from validating. This is definitely not preferred if you expect it to occur but if the event is truly exceptional, this could be the best alternative.
The basic way of representing invalid states in F# is to use the option type, which has two possible values. None represents invalid state and Some(<v>) represents a valid value <v>.
So in your case, you could write something like:
let foo =
match bar with
| <test for valid> -> Some(bar)
| _ -> None
The match construct works well if <test for valid> is actual pattern (e.g. empty list or a specific invalid number or a null value), but if it is just a boolean expression, then it is probably better to write the condition using if:
let foo =
if <test for valid> bar then Some(bar)
else None
You could do something along this lines
type Bar =
| Bar of string
| Foo of int
let (|IsValidStr|_|) x = if x = Bar "bar" then Some x else None
let (|IsValidInt|_|) x = if x = Foo 0 then Some x else None
let foo (bar:Bar) =
match bar with
| IsValidStr x -> Some x
| IsValidInt x -> Some x
| _ -> None
That is you could use active patterns to check for the actual business rules and return an Option instance
Based on what the OP wrote in the comments:
You would define a type as in the post that Fyodor linked, that captures your two possible outcomes:
type Result<'TSuccess,'TFailure> =
| Success of 'TSuccess
| Failure of 'TFailure
Your validation code becomes:
let checkBool str =
match bool.TryParse str with
| true, b -> Success b
| _ -> Failure ("I can't parse this: " + str)
When using it, again use match:
let myInput = "NotABool"
match checkBool myInput with
| Success b -> printfn "I'm happy: %O" b
| Failure f -> printfn "Did not like because: %s" f
If you only would like to continue with valid bools, your code can only fail on invalid arguments, so you would do:
let myValidBool =
match checkBool myInput with
| Success b -> b
| Failure f -> failwithf "I did not like the args because: %s" f
I'm trying to memoize a member function of a class, but every time the member is called (by another member) it makes a whole new cache and 'memoized' function.
member x.internal_dec_rates =
let cache = new Dictionary< Basis*(DateTime option), float*float>()
fun (basis:Basis) (tl:DateTime option) ->
match cache.TryGetValue((basis,tl)) with
| true, (sgl_mux, sgl_lps) -> (sgl_mux, sgl_lps)
| _ ->
let (sgl_mux, sgl_lps) =
(* Bunch of stuff *)
cache.Add((basis,tl),(sgl_mux,sgl_lps))
sgl_mux,sgl_lps
I'm using Listing 10.5 in "Real World Functional Programming" as a model. I've tried using a memoization higher-order function and that doesn't help. The above listing has the memoization built in directly.
The problem is, when I call it e.g.
member x.px (basis:Basis) (tl: DateTime option) =
let (q,l) = (x.internal_dec_rates basis tl)
let (q2,l2) = (x.internal_dec_rates basis tl)
(exp -q)*(1.-l)
execution goes to the 'let cache=...' line, defeating the whole point. I put in the (q2,l2) line in order to make sure it wasn't a scope problem, but it doesn't seem to be.
In fact I did a test using Petricek's code as a member function and that seems to have the same issue:
// Not a member function
let memo1 f =
let cache = new Dictionary<_,_>()
(fun x ->
match cache.TryGetValue(x) with
| true, v -> v
| _ -> let v = f x
cache.Add(x,v)
v
)
member x.factorial = memo1(fun y->
if (y<=0) then 1 else y*x.factorial(y-1))
Even the internal recursion of x.factorial seems to set up a new 'cache' for each level.
What am I doing wrong, and how can I make this work?
In response to your comment on Jack's answer, this doesn't have to become tedious. Given a memoize function:
let memoize f =
let cache = Dictionary()
fun x ->
match cache.TryGetValue(x) with
| true, v -> v
| _ ->
let v = f x
cache.Add(x, v)
v
Define each of your functions as let-bound values and return them from your methods:
type T() as x =
let internalDecRates = memoize <| fun (basis: Basis, tl: DateTime option) ->
(* compute result *)
Unchecked.defaultof<float * float>
let px = memoize <| fun (basis, tl) ->
let (q,l) = x.InternalDecRates(basis, tl)
let (q2,l2) = x.InternalDecRates(basis, tl)
(exp -q)*(1.-l)
member x.InternalDecRates = internalDecRates
member x.Px = px
The only "boilerplate" is the let binding and call to memoize.
EDIT: As kvb noted, in F# 3.0 auto-properties allow a more concise solution:
type T() as x =
member val InternalDecRates = memoize <| fun (basis: Basis, tl: DateTime option) ->
(* compute result *)
Unchecked.defaultof<float * float>
member val Px = memoize <| fun (basis, tl) ->
let (q,l) = x.InternalDecRates(basis, tl)
let (q2,l2) = x.InternalDecRates(basis, tl)
(exp -q)*(1.-l)
I see a lot of long answers here; the short answer is that
member x.P = code()
defines a property P which has a getter that runs code() every time P is accessed. You need to move the cache creation into the class's constructor, so that it will only run once.
As others already said, this cannot be done just by defining a single member in F# 2.0. You either need a separate field (let bound value) for a cache or for a local function that is memoized.
As mentioned by kvb, in F# 3.0, you can do this using member val which is a property that is initialized when the object is created (and has an automatically generated backing field where the result is stored). Here is a complete sample that demonstrates this (it will work in Visual Studio 2012):
open System.Collections.Generic
type Test() =
/// Property that is initialized when the object is created
/// and stores a function value 'int -> int'
member val Foo =
// Initialize cache and return a function value
let cache = Dictionary<int, int>()
fun arg ->
match cache.TryGetValue(arg) with
| true, res -> res
| false, _ ->
let res = arg * arg
printfn "calculating %d" arg
cache.Add(arg, res)
res
// Part of the property declaration that instructs
// the compiler to generate getter for the property
with get
The with get part of the declaration can be omitted, but I include it here to make the sample clearer (you can also use with get, set to get a mutable property). Now you can call test.Foo as a function and it caches the value as required
let t = Test()
t.Foo(10)
t.Foo(10)
The only problem with this approach is that t.Foo is actually compiled as a property that returns a function (instead of being compiled as a method). This is not a big problem when you use the class from F#, but it would be a problem if you were calling it from C# (because C# would see the member as a property of type FSharpFunc<int, int>, which is hard to use).
John is correct -- you need to move the cache dictionary into a private, let-bound member of the type.
Type members are compiled a bit differently than let-bound values in modules, which is the reason for the difference in behavior. If you copy/paste the body of your x.internal_dec_rates method and assign it to a let-bound value in a module, it should work correctly then, because the F# compiler will compile it as a closure which gets created once and then assigned to a static readonly field of the module.
A couple of other tips, for good measure:
Type member methods can use optional parameters -- so you can slightly simplify the method signature if you like.
You can create the cache key just once and reuse it (this also helps avoid mistakes).
You can simplify the (sgl_mux, sgl_lps) pattern-matching code by just assigning the tuple a name (e.g., value), since you're just returning the whole tuple anyway.
Here's my take on your code:
type FooBar () =
let cache = new Dictionary< Basis*(DateTime option), float*float>()
member x.internal_dec_rates (basis : Basis, ?tl : DateTime) =
let key = basis, tl
match cache.TryGetValue key with
| true, value -> value
| _ ->
// sgl_mux, sgl_lps
let value =
(* Bunch of stuff *)
cache.Add (key, value)
value
You need to move the dictionary outside the function call - like
let cache = new Dictionary< Basis*(DateTime option), float*float>()
member x.internal_dec_rates =
fun (basis:Basis) (tl:DateTime option) ->
match cache.TryGetValue((basis,tl)) with
| true, (sgl_mux, sgl_lps) -> (sgl_mux, sgl_lps)
| _ ->
let (sgl_mux, sgl_lps) =
(* Bunch of stuff *)
cache.Add((basis,tl),(sgl_mux,sgl_lps))
sgl_mux,sgl_lps
This way the cache persists across the function calls. Your memo1 has the same problem. In the original version, you create a new cache every time you call the function, this way we just have a single cache, which persists across function calls.
In addition to the other answers, note that in F# 3.0 you can use automatically implemented properties, which will behave as you want:
member val internal_dec_rates = ...
Here, the right hand side is evaluated only once, but everything is self-contained.
Sorry about the vague title, but part of this question is what these two syntax styles are called:
let foo1 x =
match x with
| 1 -> "one"
| _ -> "not one"
let foo2 = function
| 1 -> "one"
| _ -> "not one"
The other part is what difference there is between the two, and when I would want to use one or the other?
The pro for the second syntax is that when used in a lambda, it could be a bit more terse and readable.
List.map (fun x -> match x with | 1 -> "one" | _ -> "not one") [0;1;2;3;1]
vs
List.map (function 1 -> "one" | _ -> "not one") [0;1;2;3;1]
The match version is called a "pattern matching expression". The function version is called a "pattern matching function". Found in section 6.6.4 of the spec.
Using one over the other is a matter of style. I prefer only using the function version when I need to define a function that is only a match statement.
The function version is a short hand for the full match syntax in the special case where the match statement is the entire function and the function only has a single argument (tuples count as one). If you want to have two arguments then you need to use the full match syntax*. You can see this in the types of the following two functions.
//val match_test : string -> string -> string
let match_test x y = match x, y with
| "A", _ -> "Hello A"
| _, "B" -> "Hello B"
| _ -> "Hello ??"
//val function_test : string * string -> string
let function_test = function
| "A", _ -> "Hello A"
| _, "B" -> "Hello B"
| _ -> "Hello ??"
As you can see match version takes two separate arguments whereas the function version takes a single tupled argument. I use the function version for most single argument functions since I find the function syntax looks cleaner.
*If you really wanted to you can get the function version to have the right type signature but it looks pretty ugly in my opinion - see example below.
//val function_match_equivalent : string -> string -> string
let function_match_equivalent x y = (x, y) |> function
| "A", _ -> "Hello A"
| _, "B" -> "Hello B"
| _ -> "Hello ??"
They do the same thing in your case -- the function keyword acts like a combination of the fun keyword (to produce an anonymous lambda) followed by the match keyword.
So technically these two are the same, with the addition of a fun:
let foo1 = fun x ->
match x with
| 1 -> "one"
| _ -> "not one"
let foo2 = function
| 1 -> "one"
| _ -> "not one"
Just for completeness sake, I just got to page 321 of Expert FSharp:
"Note, Listing 12-2 uses the expression form function pattern-rules -> expression. This is equivalent to (fun x -> match x with pattern-rules -> expression) and is especially convenient as a way to define functions working directly over discriminated unions."
function only allows for one argument but allows for pattern matching, while fun is the more general and flexible way to define a function. Take a look here: http://caml.inria.fr/pub/docs/manual-ocaml/expr.html
The two syntaxes are equivalent. Most programmers choose one or the other and then use it consistently.
The first syntax remains more readable when the function accepts several arguments before starting to work.
This is an old question but I will throw my $0.02.
In general I like better the match version since I come from the Python world where "explicit is better than implicit."
Of course if type information on the parameter is needed the function version cannot be used.
OTOH I like the argument made by Stringer so I will start to use function in simple lambdas.