Reputation: 2415
Given the following:
type IFruit = interface end
type Avocado = { color : string; age : int } interface IFruit
let (|AvocadoTexture|) (a : Avocado) = if a.age < 7 then "firm" else "mushy"
... Why does this work:
let texture (f : IFruit) =
match f with
| :? Avocado as a -> if a.age < 7 then "firm" else "mushy"
| _ -> String.Empty
... but not this?
let texture (fruit : IFruit) =
match fruit with
| AvocadoTexture t -> t // "The type IFruit does not match the type Avocado"
| _ -> String.Empty
Upvotes: 2
Views: 92
Reputation: 9009
Just bear in mind that there are Partial Active Patterns and Active Patterns. Active Patterns have up to 7 tags that something can be concretely matched against. Both forms are useful.
Active Patterns are better if you want the compiler to tell you all the places where you've missed handling a case after you've decided that you need an extra one. The compiler can be configured to flag this as an error rather than a warning if you want to be extra strict about it.
open System
type IFruit = interface end
type Avocado =
{ color : string; age : int }
interface IFruit
static member tryFromIFruit(x:IFruit) =
match x with
| :? Avocado -> Some(x:?>Avocado)
| _ -> None
let (|Firm|Mushy|) (a : Avocado) = if a.age < 7 then Firm else Mushy
let texture (fruit : IFruit) =
match fruit |> Avocado.tryFromIFruit with // we're not sure if it's an Avocado.
| Some(Firm) -> "firm" // use Some(SomethingElse()) when you want to collapse an extra layer of "match" statements.
| Some(Mushy) -> "mushy"
| None -> ""
texture ( { color = "green"; age = 4 } :> IFruit)
documentation: https://learn.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/active-patterns
Upvotes: 2
Reputation: 6629
fruit
may be any IFruit
, but the AvocadoTexture
Active Pattern only accepts the specific implementation Avocado
, as per the type annotation of a
.
If you want the Active Pattern to accept any IFruit
, but only return a useful value for an Avocado
, you can make it partial:
let (|AvocadoTexture|_|) (f : IFruit) =
match f with
| :? Avocado as a ->
if a.age < 7 then "firm" else "mushy"
|> Some
| _ -> None
Now your texture
function works as you wanted:
let texture (fruit : IFruit) =
match fruit with
| AvocadoTexture t -> t
| _ -> String.Empty
Upvotes: 6