Function with flexible type argument and return value?

I am trying to write a function that takes a particular type or any of its subtypes as one of its arguments, then returns the value of the type or any of its subtypes.

[<AbstractClass>]
type Spreader () =
    abstract Fn : unit -> unit

type Fire () =
    inherit Spreader ()
    override self.Fn () = ()

type Disease () =
    inherit Spreader ()
    override self.Fn () = ()

let spread (spr:#Spreader) : #Spreader =
    match spr with
    | :? Fire -> Fire ()
    | :? Disease -> Disease ()
    | _ -> failwith "I don't get it"

Obviously this does not work, but you get what I am trying to do.

First, I applied an abstract function in the Spreader type and redefined it in subtypes, but this required a raise, which I am trying to avoid.

Is this doable? I look at generics, but I do not quite understand their implementation of F #.

EDIT 2010.07.08 1730 PST

, , . , , , , , . :

type strength = float32

type Spreader =
    | Fire of strength
    | Disease of strength

    member self.Spread () =
        match self with
        | Fire str -> Fire str
        | Disease str -> Disease str

    member self.Burn () =
        match self with
        | Fire str -> Fire str
        | _ -> failwith "Only fire burns"

Spread , , Fire Burning, Disease, .

- , , Disease.Burn, , :

member self.Burn () =
    match self with
    | Fire str -> Some(Fire str)
    | _ -> None

Burn Fire Spreader .

, ; , , , , . , Spreader , , , , , member.strength , . (, | Disease str → ...)

, , Spread Burn Spreader, (1) ( ), ( 2) , , SpreadFire SpreadDisease ( ).

noob F #, .:)

EDIT 2010.07.09 0845 PST

: " ?"

, .

: " , Speader, ?"

, , Burn Spreader. , . Spreader Spreader. ( .)

: " Fn?"

, , , .

: " ?"

, . , , .

: " float32?"

.

John Harrop: "What is the specific problem you are trying to solve?"

Code exchange for related types while maintaining readability.

Interestingly, the solution you proposed is exactly the solution I tried first (I was on this F # for only a week or so), but I dropped it because I was not comfortable with the idea of ​​wrapping my main types in DU as a workaround for the inability to overload functions defined by external type definitions. I'm just paranoid about getting on the wrong foot with fundamental types (partly due to the deplorable lack of F # refactoring in VS2010). Functional programming is a subject of great interest to me right now, and I pretty much just catch it for understanding.

EDIT 2010.07.09 2230 PST

, I/m ( http://briancarper.net/blog/315/functional-programming-hurts-me - F #, , ).

, - (, ) , (). FP , , , sh * t .

+3
3

, :

let spread (spr: Spreader) =
  match spr with
  | :? Fire -> (Fire() :> Spreader)
  | :? Disease -> (Disease() :> Spreader)

. ?

, . ? , burn Speader, ? Fn? ? strength float32? , ?!

:

type fire = ...

let burn fire = ...

type spreader = Disease | Fire of fire

let spread = function
  | Disease -> ...
  | Fire fire -> ...

, , , - . ( ), .

+4

F # ( ), , (, ).

, spread Spreader . :

let foo< 'T when 'T :> Spreader >(arg:'T) : 'T =
  // some implementation here

'T Spreader, foo , .

, :

let foo< 'T when 'T :> Spreader >(arg:'T) : 'T =
  match box arg with 
  | :? Fire -> (box (Fire())) :?> 'T
  | :? Disease -> (box (Disease())) :?> 'T

, , , . , .


Jon spread2 Brian, , , , , :

let fire = new Fire()
let fire2 = foo fire       // 'fire2' has type 'Fire'
fire2.FireSpecificThing()
+4

spread1 spread2 , , , .

[<AbstractClass>] 
type Spreader () = 
    abstract Fn : unit -> unit 

type Fire () = 
    inherit Spreader () 
    override self.Fn () = () 

type Disease () = 
    inherit Spreader () 
    override self.Fn () = () 

let fire = new Fire()
let disease = new Disease()

let spread1<'t when 't :> Spreader>(spr:'t) : 't = 
    spr

printfn "%A" (spread1 fire)
printfn "%A" (spread1 disease)

let spread2(spr:Spreader) : Spreader = 
    match spr with
    | :? Fire -> upcast disease
    | :? Disease -> upcast fire
    | _ -> failwith "hmmm"

printfn "%A" (spread2 fire)
printfn "%A" (spread2 disease)

, , - , , . #. . ,

let spread (spr:Spreader) : Spreader = 
    match spr with 
    | :? Fire -> upcast Fire () 
    | :? Disease -> upcast Disease () 
    | _ -> failwith "I don't get it" 

. Spread .

As an aside, you almost never need the "flexible types" ( #type) in F #, this is often the smell of code if you think you need to use them.

+2
source

Source: https://habr.com/ru/post/1753802/


All Articles