Consider the following simple example.
type PaymentInstrument =
| Check of string
| CreditCard of string * DateTime
let printInstrumentName instrument =
match instrument with
| Check number-> printfn "check"
| CreditCard (number, expirationDate) -> printfn "card"
let printRequisites instrument =
match instrument with
| Check number -> printfn "check %s" number
| CreditCard (number, expirationDate) -> printfn "card %s %A" number expirationDate
As you can see the same pattern matching logic is repeated in two functions. If I would use OOP I would create interface IPaymentInstrument, define two operations:
PrintInstrumentName and PrintRequisites
and then implement classes - one per payment instrument. To instantiate instrument depending on some external conditions I would use (for example) the factory pattern (PaymentInstrumentFactory).
If I would need to add a new payment instrument, I just need to add a new class which implements IPaymentInstrument interface and update factory instantiating logic. Other code that uses these classes remains as is.
But if I use the functional approach I should update each function where pattern matching on this type exists.
If there will be a lot of functions using PaymentInstrument type that will be a problem.
How to eliminate this problem using functional approach?
As Patryk Ćwiek points out in the comment above, you're encountering the Expression Problem, so you'll have to choose one or the other.
If the ability to add more data types is more important to you than the ability to easily add more behaviour, then an interface-based approach may be more appropriate.
In F#, you can still define object-oriented interfaces:
type IPaymentInstrument =
abstract member PrintInstrumentName : unit -> unit
abstract member PrintRequisites : unit -> unit
You can also create classes that implement this interface. Here's Check, and I'll leave CreditCard as an exercise to the reader:
type Check(number : string) =
interface IPaymentInstrument with
member this.PrintInstrumentName () = printfn "check"
member this.PrintRequisites () = printfn "check %s" number
Yet, if you want to go the object-oriented way, you should begin to consider the SOLID principles, one of which is the Interface Segregation Principle (ISP). Once you start applying the ISP aggressively, you'll ultimately end up with interfaces with a single member, like this:
type IPaymentInstrumentNamePrinter =
abstract member PrintInstrumentName : unit -> unit
type IPaymentInstrumentRequisitePrinter =
abstract member PrintRequisites : unit -> unit
You can still implement this in classes:
type Check2(number : string) =
interface IPaymentInstrumentNamePrinter with
member this.PrintInstrumentName () = printfn "check"
interface IPaymentInstrumentRequisitePrinter with
member this.PrintRequisites () = printfn "check %s" number
This is beginning to seem slightly ridiculous now. If you're using F#, then why go to all the trouble of defining an interface with a single member?
Why not, instead, use functions?
Both desired interface members have the type unit -> unit (not a particularly 'functionally' looking type, though), so why not pass such functions around, and dispense with the interface overhead?
With the printInstrumentName and printRequisites functions from the OP, you already have the desired behaviour. If you want to turn them into polymorphic 'objects' that 'implement' the desired interface, you can close over them:
let myCheck = Check "1234"
let myNamePrinter () = printInstrumentName myCheck
In Functional Programming, we don't call these things objects, but rather closures. Instead of being data with behaviour, they're behaviour with data.
Using Mark Seemann's answer I came to such design decision.
type PaymentInstrument =
| Check of string
| CreditCard of string * DateTime
type Operations =
{
PrintInstrumentName : unit -> unit
PrintRequisites : unit -> unit
}
let getTypeOperations instrument =
match instrument with
| Check number->
let printCheckNumber () = printfn "check"
let printCheckRequisites () = printfn "check %s" number
{ PrintInstrumentName = printCheckNumber; PrintRequisites = printCheckRequisites }
| CreditCard (number, expirationDate) ->
let printCardNumber () = printfn "card"
let printCardRequisites () = printfn "card %s %A" number expirationDate
{ PrintInstrumentName = printCardNumber; PrintRequisites = printCardRequisites }
And usage
let card = CreditCard("124", DateTime.Now)
let operations = getTypeOperations card
operations.PrintInstrumentName()
operations.PrintRequisites()
As you can see the getTypeOperations function executes the role of factory pattern. To aggregate functions in a one bunch I use simple record type (however, according to F# design guidelines http://fsharp.org/specs/component-design-guidelines/ interfaces are preferred to such decision but I am interested to do it in functional approach for now to understand it better).
I got what I wanted - pattern matching is in only one place for now.
Related
I'm experimenting with rewriting a complicated piece of code using F#.
For this particular code base, discriminated unions help me a lot, so I'm focusing on using them as much as possible. Specifically, exhaustiveness checks on DUs is helping me avoid lots and lots of bugs.
However, I'm facing a repeating pattern of having to use match ... with to the extent that the clutter in the code is offsetting the benefit I'm getting from exhaustiveness check.
I simplified the pattern I'm dealing with as much as I can and tried to come up with an example that demonstrates the structure of the code I'm writing. The real code base is a lot more complicated and it is in a completely different domain but at the language level, this example represents the issue.
Let's say we want to get some about shoppers based on a classification of shoppers: they're either cat people or dog people. The key thing here is classifying some types (tuples) via DUs.
Here are the domain types:
type PetPerson =
|CatPerson
|DogPerson
type CatFood =
|Chicken
|Fish
type DogFood =
|Burger
|Steak
//some cat food, shopper's age and address
type CatFoodShopper = CatFoodShopper of (CatFood list * int * string)
//some dog food, shopper's age and number of children
type DogFoodShopper = DogFoodShopper of (DogFood list * int * int)
Leaving aside the horrible way we're feeding the poor animals, this domain model needs a function to map PetPerson to CatFoodShopper or DogFoodShopper
At this point, my initial thought is to define a Shopper type, since I cannot return two different types from the following function, based on the results of pattern matching:
type Shopper =
|CatFShopper of CatFoodShopper
|DogFShopper of DogFoodShopper
let ShopperViaPersonality = function
|CatPerson -> CatFShopper (CatFoodShopper ([Chicken;Fish], 32, "Hope St"))
|DogPerson -> DogFShopper (DogFoodShopper ([Burger;Steak], 45, 1))
This solves the problem but then I have lots of places in the code (really a lot) where I end up with a PetPerson and need to get a CatFoodShopper or a DogFoodShopper based on what the PetPerson value is. This leads to unnecessary pattern matching for cases I know I don't have at hand. Here is an example:
let UsePersonality (x:int) (y:PetPerson) =
//x is used in some way etc. etc.
match y with
|CatPerson as c -> //how can I void the following match?
match (ShopperViaPersonality c) with
|CatFShopper (CatFoodShopper (lst,_,_))-> "use lst and return some string "
| _ -> failwith "should not have anything but CatFShopper"
|DogPerson as d -> //same as before. I know I'll get back DogFShopper
match (ShopperViaPersonality d) with
|DogFShopper (DogFoodShopper (lst, _,_)) -> "use lst and return other string"
|_ -> failwith "should not have anything but DogFShopper"
As you can see, I have to write pattern matching code even when I know I'll be getting back a particular value. I have no way of concisely associating the CatPerson value to CatFoodShopper value.
In order to improve things at the call site, I considered using F#'s way of mimicking type classes via interfaces, based on lots of example available here:
type IShopperViaPersonality<'T> =
abstract member ShopperOf: PetPerson -> 'T
let mappingInstanceOf<'T> (inst:IShopperViaPersonality<'T>) p = inst.ShopperOf p
let CatPersonShopper =
{new IShopperViaPersonality<_> with
member this.ShopperOf x =
match x with
|CatPerson -> CatFoodShopper ([Chicken;Fish], 32, "Hope St")
| _ -> failwith "This implementation is only for CatPerson"}
let CatPersonToShopper = mappingInstanceOf CatPersonShopper
let DogPersonShopper =
{new IShopperViaPersonality<_> with
member this.ShopperOf x =
match x with
|DogPerson -> DogFoodShopper ([Burger;Steak], 45, 1)
| _ -> failwith "This implementation is only for DogPerson"}
let DogPersonToShopper = mappingInstanceOf DogPersonShopper
So I no longer have a Shopper type to represent both cat food shoppers and dog food shoppers, but instead an interface defines the mapping from PetPerson values to specific shopper types. I also have individual partially applied functions to make things even easier at the call site.
let UsePersonality1 (x:int) (y:PetPerson) =
match y with
|CatPerson as c ->
let (CatFoodShopper (lst,_,_)) = CatPersonToShopper c
"use lst and return string"
|DogPerson as d ->
let (DogFoodShopper (lst,_,_)) = DogPersonToShopper d
"use lst and return string"
This approach works better when using PetPerson values, but I'm now left with the task of defining these individual functions to keep things clean at the call site.
Note that this example is meant to demonstrate the trade off between using a DU and using an interface to return different types based on the classifying DU parameter, if I may call it that. So don't hang up on my meaningless use of return values etc.
My question is: are there any other ways I can accomplish the semantics of classifying a bunch of tuple (or record) types? If you're thinking active patterns, they're not an option because in the real code base the DUs have more than seven cases, which is the limit for active patterns, in case they would be of help. So do I have any other options to improve on the above approaches?
One obvious way to go about this is to call ShopperViaPersonality before matching PetPerson, not after:
let UsePersonality (x:int) (y:PetPerson) =
//x is used in some way etc. etc.
match ShopperViaPersonality y with
| CatFShopper (CatFoodShopper (lst,_,_))-> "use lst and return some string "
| DogFShopper (DogFoodShopper (lst, _,_)) -> "use lst and return other string"
Also note that if the sole purpose of ShooperViaPersonality is to support pattern matches, you may be better off making it an active pattern:
let (|CatFShopper|DogFShopper|) = function
| CatPerson -> CatFShopper ([Chicken;Fish], 32, "Hope St")
| DogPerson -> DogFShopper ([Burger;Steak], 45, 1)
Then you can use it like this:
let UsePersonality (x:int) (y:PetPerson) =
//x is used in some way etc. etc.
match y with
| CatFShopper (lst,_,_) -> "use lst and return some string "
| DogFShopper (lst, _,_) -> "use lst and return other string"
Logically, an active pattern is pretty much the same as a DU + a function, but on syntactic level, notice how much less nesting there is now.
Is it possible to create methods or stand-alone functions in a computation expression that can later be used by one of the canonical methods of a computation expression?
I want something like this:
type FormletBuilder(ctx : HttpContext) =
let get_int =
match Int32.TryParse (ctx.Request.["foo"]) with
| (true, n) -> Some n
| _ -> None
//similar definitions for get_date, get_non_empty_str, etc...
member x.Bind (read : 'a option, f : 'a -> option 'a) =
match read with
| Some x -> f(x)
| None -> None
member x.Return (obj) = Some obj
member x.Zero () = None
let person = formlet ctx {
let! id = get_int "id"
let! name = get_non_empty_str "fullname"
return Person(id, name)
}
But the compiler complains that get_int is not defined.
let bindings in class definitions are always private. You can define a member instead.
For an easy solution, you could do:
let formlet = FormletBuilder(ctx)
let person = formlet {
let! id = formlet.get_int "id"
...
}
I understand now that what you actually want is a maybe monad, and the workflow argument is there just to make use of some syntactic sugar? If so, there are a couple other things you can consider doing:
Go Haskell on it all the way and implement a MaybeReader monad, so that both the maybe and the reader parts of it are explicit in type,
Put the sugar away - I understand you don't actually need the context in any core builder members? If so, than maybe it had no business being an argument to the builder in the first place. Have a 'clean' maybe monad, move get_int etc. into a proper module and have them take HttpContext explicitly as an argument.
If you're using F# 3.0 or later, you can define get_int etc. as custom operations of the workflow, which should effectively give you the nice syntax you want to have. Here's a good post about it by Tomas Petricek.
Combine 2. and 3. - instead of a large number of custom operations, have one - ask - which will take an HttpContext -> 'a function and apply ctx to it. Effectively a bastardized version of reader. Then you can move your get_int etc. into a proper module.
A discriminated union in F# is compiled to an abstract class and its options become nested concrete classes.
type DU = A | B
DU is abstract while DU.A and DU.B are concrete.
With ServiceStack, the serialization of types to JSON strings and back can be customized with functions. With respect to the DU type, here's how I could do it in C#.
using ServiceStack.Text;
JsConfig<DU.A>.SerializeFn = v => "A"; // Func<DU.A, String>
JsConfig<DU.B>.SerializeFn = v => "B"; // Func<DU.B, String>
JsConfig<DU>.DeserializeFn = s =>
if s == "A" then DU.NewA() else DU.NewB(); // Func<String, DU>
Is F# aware of its discriminated unions' compiled forms? How would I get the type of DU.A in F# at compile time?
typeof<DU> // compiles
typeof<DU.A> // error FS0039: The type 'A' is not defined
typeof<A> // error FS0039: The type 'A' is not defined
I can easily enough register a function for deserialization in F#.
open System
open ServiceStack.Text
JsConfig<DU>.RawDeserializeFn <-
Func<_, _>(fun s -> printfn "Hooked"; if s = "A" then A else B)
Is it possible to register serialize functions wholly in F# for the concrete types DU.A and DU.B?
Whilst all the behaviour (the abstract classes etc.) is not just an implemenation detail, it is actually defined by the spec, these things are not accesible from F# - this is a quote from the spec
A compiled union type U has:
· One CLI static getter property U.C for each null union case
C. This property gets a singleton object that represents each such
case.
· One CLI nested type U.C for each non-null union case C. This
type has instance properties Item1, Item2.... for each field of the
union case, or a single instance property Item if there is only one
field. However, a compiled union type that has only one case does not
have a nested type. Instead, the union type itself plays the role of
the case type.
· One CLI static method U.NewC for each non-null union case C.
This method constructs an object for that case.
· One CLI instance property U.IsC for each case C. This
property returns true or false for the case.
· One CLI instance property U.Tag for each case C. This
property fetches or computes an integer tag corresponding to the case.
· If U has more than one case, it has one CLI nested type
U.Tags. The U.Tags typecontains one integer literal for each case, in
increasing order starting from zero.
· A compiled union type has the methods that are required to
implement its auto-generated interfaces, in addition to any
user-defined properties or methods.
These methods and properties may not be used directly from F#.
However, these types have user-facing List.Empty, List.Cons,
Option.None, and Option.Some properties and/or methods.
Importantly, "these methods and properties may not be used from F#".
Daniel is correct, you can do this by registering serialization functions for the base type DU. Here is a fuller example
open System
open ServiceStack.Text
type DU = A | B
let serialize = function
| A -> "A"
| B -> "B"
let deserialize = function
| "A" -> A
| "B" -> B
| _ -> failwith "Can't deserialize"
JsConfig<DU>.SerializeFn <- Func<_,_>(serialize)
JsConfig<DU>.DeSerializeFn <- Func<_,_>(deserialize)
let value = [| A; B |]
let text = JsonSerializer.SerializeToString(value)
let newValue = JsonSerializer.DeserializeFromString<DU[]>(text)
Result:
val value : DU [] = [|A; B|]
val text : string = "["A","B"]"
val newValue : DU [] = [|A; B|]
The fact that a DU in F# is a single type is key to its usefulness. The F# approach would be to use pattern matching:
JsConfig<DU>.SerializeFn <- function
| A -> "A"
| B -> "B"
This should work because the union cases are not only nested types in C#, but subtypes as well. Of course if ServiceStack doesn't consider base type serializers then this won't work.
Suppose I have the following DU:
type Something =
| A of int
| B of string * int
Now I use it in a function like this:
let UseSomething = function
| A(i) -> DoSomethingWithA i
| B(s, i) -> DoSomethingWithB s i
That works, but I've had to deconstruct the DU in order to pass it to the DoSomethingWith* functions. It feels natural to me to try to define DoSomethingWithA as:
let DoSomethingWithA (a: Something.A) = ....
but the compiler complains that the type A is not defined.
It seems entirely in keeping with the philosophy of F# to want to restrict the argument to being a Something.A, not just any old int, so am I just going about it the wrong way?
The important thing to note is that A and B are constructors of the same type Something. So you will get inexhaustive pattern matching warning if you try to use A and B cases separately.
IMO, deconstructing all cases of DUs is a good idea since it is type-safe and forces you to think of handling those cases even you don't want to. The problem may arise if you have to deconstruct DUs repetitively in the same way. In that case, defining map and fold functions on DUs might be a good idea:
let mapSomething fa fb = function
| A(i) -> fa i
| B(s, i) -> fb s i
Please refer to excellent Catamorphism series by #Brian to learn about fold on DUs.
That also said that your example is fine. What you really process are string and int values after deconstruction.
You can use Active Patterns to consume two cases separately:
let (|ACase|) = function A i -> i | B _ -> failwith "Unexpected pattern B _"
let (|BCase|) = function B(s, i) -> (s, i) | A _ -> failwith "Unexpected pattern A _"
let doSomethingWithA (ACase i) = ....
but inferred type of doSomethingWithA is still the same and you get an exception when passing B _ to the function. So it's a wrong thing to do IMO.
The other answers are accurate: in F# A and B are constructors, not types, and this is the traditional approach taken by strongly typed functional languages like Haskell or the other languages in the ML family. However, there are other approaches - I believe that in Scala, for example, A and B would actually be subclasses of Something, so you could use those more specific types where it makes sense to do so. I'm not completely sure what tradeoffs are involved in the design decision, but generally speaking inheritance makes type inference harder/impossible (and true to the stereotype type inference in Scala is much worse than in Haskell or the ML languages).
A is not a type, it is just a constructor for Something. There's no way you can avoid pattern matching, which is not necessarily a bad thing.
That said, F# does offer a thing called active patterns, for instance
let (|AA|) = function
| A i -> i
| B _ -> invalidArg "B" "B's not allowed!"
which you can then use like this:
let DoSomethingWithA (AA i) = i + 1
But there's no real reason why you would want to do that! You still do the same old pattern matching under the hood, plus you risk the chance of a runtime error.
In any case, your implementation of UseSomething is perfectly natural for F#.
Problem Summary
At the moment when using f# I must explicitly coerce a value to the parent type of its type in order to get pattern matching expressions to type check correctly. I would ideally like a neater way of doing.
Example
Suppose I have some class hierachy:
type Foo () =
abstract member Value : unit -> string
type A (i:int) =
inherit Foo ()
override this.Value () = i.ToString()
type B (s:string) =
inherit Foo ()
override this.Value () = s
Ideally, and in some programming languages in normally, I would write the equivalent of the following:
let bar (i:int) : Foo =
match i with
| 1 -> B "one"
| _ -> A i
However this fails to type check correctly, giving me the error, "This expression was expected to have type Foo but here has type B". I don't understand why the compiler doesn't have enough information to infer a common super type for the match expression and then check that the common super type is 'Foo'.
At present I am forced to provide an explicit coercion for every case in the pattern match:
let bar2 (i:int) : Foo =
match i with
| 1 -> (B "one") :> Foo
| _ -> (A i) :> Foo
I would like to avoid this.
Further Notes
Intuition suggests that this is a result of a more general issue. I would have thought though that something as common as pattern matching, or if statements which also exhibit the same property, would have a type checking rule to account for common super types.
Before anyone suggests - I appreciate that if A or B were Object Expressions this would work, but my real example is creating instances of C# classes where they are normal classes.
Is there a way for me to declare functions to implicitly convert types, as for example scala has, so I could apply automatic conversions for the module where I'm doing this generation?
Thanks for any help on this matter.
I would use upcast, a la
[<AbstractClass>]
type Foo () =
abstract member Value : unit -> string
type A (i:int) =
inherit Foo ()
override this.Value () = i.ToString()
type B (s) =
inherit Foo ()
override this.Value () = s
let bar2 i : Foo =
match i with
| 1 -> upcast B "one"
| _ -> upcast A i
You still have to add it to every branch, but this is often preferable to casting to the type, since often the typename is like 20 or 30 characters long (MyNamespace.ThisThingy), whereas upcast is just 6 characters.
But, briefly, the language rules don't allow for anything else, the types of all the branches have to be equal.
I've seen this question a couple of times before, but I just realized that there is quite an interesting way to workaround the issue (without any significant negative effects such as big runtime overhead).
You can use a very simple computation expression that has only Return member. The builder will have a type parameter and Return will expect values of this type. The trick is, that F# does insert automatic upcasts when calling a member. Here is the declaration:
type ExprBuilder<'T>() =
member x.Return(v:'T) = v
let expr<'T> = ExprBuilder<'T>()
To write a simple pattern matching that returns anything as obj, you can now write:
let foo a = expr<obj> {
match a with
| 0 -> return System.Random()
| _ -> return "Hello" }
You still have to be explicit about the return type (when creating the computation expression), but I find the syntax quite neat (but it is definitely a tricky use that could confuse people who'll see it for the first time).