F# and duck-typing

后端 未结 3 629
一向
一向 2021-01-04 02:30

Let\'s say I defined in F# the following two types:

type Dog = { DogName:string; Age:int }
type Cat = { CatName:string; Age:int }

I was exp

相关标签:
3条回答
  • 2021-01-04 02:59

    Usually what is meant by F# duck-typing is a compile-time polymorphism. Syntax is a little weirder, but you should be able to work it out from the following example -

    module DuckTyping
    
    // Demonstrates F#'s compile-time duck-typing.
    
    type RedDuck =
        { Name : string }
        member this.Quack () = "Red"
    
    type BlueDuck =
        { Name : string }
        member this.Quack () = "Blue"
    
    let inline name this =
        (^a : (member Name : string) this)
    
    let inline quack this =
        (^a : (member Quack : unit -> string) this)
    
    let howard = name { RedDuck.Name = "Howard" }
    let bob = name { BlueDuck.Name = "Bob" }
    let red = quack { RedDuck.Name = "Jim" }
    let blue = quack { BlueDuck.Name = "Fred" }
    

    Remember, this polymorphism only works at compile-time!

    0 讨论(0)
  • 2021-01-04 03:03

    FSharp.Interop.Dynamic (on nuget) provides a DLR based implementation of the dynamic operator (real dynamic duck typing)

    let isOld x = x?Age >= 65
    
    0 讨论(0)
  • 2021-01-04 03:05

    You can define an inline function with a member constraint, or go the classic route and use an interface (which would probably be preferred in this case).

    let inline isOld (x:^T) = (^T : (member Age : int) x) >= 65
    

    EDIT

    I just remembered this won't work for record types. Technically their members are fields, although you can amend them with members using with member .... You would have to do that to satisfy an interface anyway.

    For reference, here's how you would implement an interface with a record type:

    type IAging =
      abstract Age : int
    
    type Dog = 
      { DogName : string
        Age : int } 
      interface IAging with
        member this.Age = //could also be `this.Age = this.Age`
          let { DogName = _; Age = age } = this
          age
    
    0 讨论(0)
提交回复
热议问题