Statically resolved string conversion function in F#

折月煮酒 提交于 2019-12-23 19:09:58

问题


I'm trying to create a function in F# that will convert certain types to a string, but not others. The objective is so that a primitive can be passed but a complex object cannot be passed by accident. Here's what I have so far:

type Conversions =
    static member Convert (value:int) =
        value.ToString()
    static member Convert (value:bool) =
        value.ToString()

let inline convHelper< ^t, ^v when ^t : (static member Convert : ^v -> string) > (value:^v) =
    ( ^t : (static member Convert : ^v -> string) (value))

let inline conv (value:^v) = convHelper<Conversions, ^v>(value)

Unfortunately, my conv function gets the following compile-time error:

A unique overload for method 'Convert' could not be determined based on type information
prior to this program point. A type annotation may be needed. Candidates: 
    static member Conversions.Convert : value:bool -> string, 
    static member Conversions.Convert : value:int -> string

What am I doing wrong?


回答1:


This seems to work:

type Conversions = Conversions with 
    static member ($) (Conversions, value: int) = value.ToString()
    static member ($) (Conversions, value: bool) = value.ToString()

let inline conv value = Conversions $ value

conv 1 |> ignore
conv true |> ignore
conv "foo" |> ignore //won't compile



回答2:


For some reason it seems using (^t or ^v) in the constraint instead of just ^v makes it work.

type Conversions =
    static member Convert (value:int) =
        value.ToString()
    static member Convert (value:bool) =
        value.ToString()

let inline convHelper< ^t, ^v when (^t or ^v) : (static member Convert : ^v -> string)> value =
    ( (^t or ^v) : (static member Convert : ^v -> string) (value))

let inline conv value = convHelper<Conversions, _>(value)

Of course it means the function will also compile if the argument's type has a static method Convert from itself to string, but it's highly unlikely to ever bite you.




回答3:


Well, Daniel's answer worked. Here's what I wanted in the end:

type Conversions = Conversions with
    static member ($) (c:Conversions, value:#IConvertible) =
        value.ToString()
    static member ($) (c:Conversions, value:#IConvertible option) =
        match value with
        | Some x -> x.ToString()
        | None -> ""

let inline conv value = Conversions $ value

The IConvertible interface type is just a convenient way for me to capture all primitives.

This results in the following behavior (FSI):

conv 1         // Produces "1"
conv (Some 1)  // Produces "1"
conv None      // Produces ""
conv obj()     // Compiler error


来源:https://stackoverflow.com/questions/21538881/statically-resolved-string-conversion-function-in-f

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!