I guess the question is how to construct PersonName
objects (as those are the input for your function).
This is quite easy - just use one of the constructors FirstOnly
, LastOnly
or FirstLast
:
let firstOnly = FirstOnly "Tom"
let lastOnly = LastOnly "Hengs"
let firstLast = FirstLast ("Tom", "Hengs")
and you can use them like this:
constructQuery firstOnly
constructQuery lastOnly
constructQuery firstLast
background
You see PersonName
is an algebraic datatype with it's 3 constructors and the constructQuery
matches it's only parameter for them. In VisualStudio (or MonoDevelop) you should be able to get a tooltip with the types for each part of this - you should do this all the times, because types are a big part understanding.
other Ways to call this function
you can use the pipe-operator |>
and do this in one go:
FirstOnly "Tom"
|> constructQuery
of course you can use it without this operator too:
constructQuery (LastOnly "Hengs")
but here you need the parens because without them you would plug the function LastOnly
(and yes this is a function String -> PersonName
) into the function constructQuery
and then apply the string like this:
constructQuery LastOnly "Hengs" = (constructQuery LastOnly) "Hengs" // error: compiler complains about mismatched types
because LastOnly
is really a function (sadly this is not the case for C# constructors) you can do cool stuff like this too:
// Pipes all the way
"Hengs" |> LastOnly |> constructQuery
// this is another function String -> PersonName
let constructFromLastOnly = LastOnly >> constructQuery
// you can call it like this
constructFromLastOnly "Hengs"
// etc. ... imagine
another alternative is to use the backwards pipe <|
(not so idiomatic):
constructQuery <| LastOnly "Hengs"
where you don't need the parens either
Remarks
I would encourage you (even if the compiler don't really needs it) to give the types for top-level functions (thouse you want to use from other parts of your program):
let constructQuery (personName : PersonName) : () =
match personName with
// ...
Did you see that you don't really need personName
besides the call to match
?
This is so common that there is another/shorter way to write this:
let constructQuery = function
| FirstOnly(firstName) -> printf "May I call you %s?" firstName
| LastOnly(lastName) -> printf "Are you Mr. or Ms. %s?" lastName
| FirstLast(firstName, lastName) -> printf "Are you %s %s?" firstName lastName
or with a signature:
let constructQuery : PersonName -> () =
function
| FirstOnly(firstName) -> printf "May I call you %s?" firstName
| LastOnly(lastName) -> printf "Are you Mr. or Ms. %s?" lastName
| FirstLast(firstName, lastName) -> printf "Are you %s %s?" firstName lastName
And finally - I don't like the fact that you mix printf
in there.
See a function returning unit ()
is never pure and you mix concerns. Why not like this:
let constructQuery : PersonName -> string =
function
| FirstOnly(firstName) -> sprintf "May I call you %s?" firstName
| LastOnly(lastName) -> sprintf "Are you Mr. or Ms. %s?" lastName
| FirstLast(firstName, lastName) -> sprintf "Are you %s %s?" firstName lastName
and use it like this:
FirstOnly "Tom"
|> constructQuery
|> Console.WriteLine
so you can reuse it for example in a WPF app or in a logging scenario where the console is not avaiable.