Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有没有可能使下面的例子在F#中完全多态?_F# - Fatal编程技术网

有没有可能使下面的例子在F#中完全多态?

有没有可能使下面的例子在F#中完全多态?,f#,F#,我想知道是否有一种方法可以让类型实现上面示例中我想要的功能,或者我是否最终达到了F#的类型系统的限制。实际上,有一种方法可以实现上述功能,即将所有类型放入一个DU中,然后在DU类型上进行模式匹配,如下所示: type Mul = Mul with member inline __.Op(a: ^a,b: ^a) = a*b type Div = Div with member inline __.Op(a: ^a,b: ^a) = a/b type Add = Add with member i

我想知道是否有一种方法可以让类型实现上面示例中我想要的功能,或者我是否最终达到了F#的类型系统的限制。实际上,有一种方法可以实现上述功能,即将所有类型放入一个DU中,然后在DU类型上进行模式匹配,如下所示:

type Mul = Mul with member inline __.Op(a: ^a,b: ^a) = a*b
type Div = Div with member inline __.Op(a: ^a,b: ^a) = a/b
type Add = Add with member inline __.Op(a: ^a,b: ^a) = a+b
type Sub = Sub with member inline __.Op(a: ^a,b: ^a) = a-b

let inline op x a b =
    (^a: (member Op: ^b * ^b -> ^b) x,a,b)

let inline tup2 a b c d = op Mul a b, op Mul c d
let inline tup2' f a b c d = op f a b, op f c d

let a = tup2 1 2 3.0f 4.0f
//let b = tup2' Mul 1 2 3.0f 4.0f //Gives a type error.

但假设第一个例子有效,它将是一个更动态的解决方案。遗憾的是,在参数中按名称传递高阶函数并将其内联以使其成为通用函数是不可能的。

大多数现代类型系统的这一限制在kvb对的回答中得到了很好的解释

这里有一个解决方法,基于那里建议的黑客。事实上,它与您的代码非常相似,但不太冗长

type Operation = 
    | Mul 
    | Add
    | Sub
    | Div
    member inline t.Op a b = 
        match t with 
        | Mul -> a * b
        | Add -> a + b
        | Sub -> a - b
        | Div -> a / b
let inline map' (f: Operation) a b c d =
    (f.Op a b, f.Op c d)
map' Mul 1 2 3.0f 4.0f
其思想是,在本例中,不是定义一个函数,而是用一个方法(您已经这样做了)定义一个类型,它将是一个运算符,这意味着apply

因此,您将编写
f$x
,而不是执行
fx

更新

如前所述,您的代码离该答案中建议的解决方案不远。 下面是一个更接近原始代码的工作示例:

type Mul = Mul with static member inline ($) (Mul, a: ^a) = fun (b: ^a) -> a*b
type Div = Div with static member inline ($) (Div, a: ^a) = fun (b: ^a) -> a/b
type Add = Add with static member inline ($) (Add, a: ^a) = fun (b: ^a) -> a+b
type Sub = Sub with static member inline ($) (Sub, a: ^a) = fun (b: ^a) -> a-b

let inline tup2' f a b c d = (f $ a) b, (f $ c) d

let b = tup2' Mul 1 2 3.0f 4.0f
这基本上是您的原始代码,但使用静态方法,并在约束中使用
。通过这样做,编译器不会提前解决约束,因此它可以工作


我使用运算符是因为它不太冗长,在本例中,我喜欢它的读取方式,因为Haskell
$
表示函数应用程序。

这很有趣,但即使现在我知道了怎么做,我也不明白为什么仅仅用内联助手调用函数是不起作用的。我试着改编你的例子,但我还是不确定。编译器尝试解析运算符的方式有什么特殊之处吗?如果我把它定义为
let inline op x a=x$a
它就可以工作,但是如果我做了
let inline op x a=(^a:(静态成员($):^a*^b->^c)x,a)
我根本无法让它工作。@Gustavo:你是说空间很大吗?(我看到的唯一区别是
x,a
中的空格)@Gustavo他问你对我的评论,你忘了修改。”您的约束不是100%相同,它应该是
让内联op x a=(^a:(静态成员($):^a*^b->^c)x,a)
“我猜您是想写”您的约束不是100%相同,它应该是
让内联op x a=(^a或^b):(静态成员($):^a*^b->^c)x,a)
“MarkoGrdinic,@ildjarn我的错误。这正是我的意思。很抱歉我造成了混乱,我将删除该评论以减少噪音。
type Mul = Mul with static member inline Op(Mul, a: ^a,b: ^a) = a*b
type Div = Div with static member inline Op(Div, a: ^a,b: ^a) = a/b
type Add = Add with static member inline Op(Add, a: ^a,b: ^a) = a+b
type Sub = Sub with static member inline Op(Sub, a: ^a,b: ^a) = a-b

let inline op x a b = ((^a or ^b): (static member Op: ^a * ^b  * ^b -> ^b) (x, a, b))

let inline tup2 a b c d = op Mul a b, op Mul c d
let inline tup2' f a b c d = op f a b, op f c d

let a = tup2 1 2 3.0f 4.0f
let b = tup2' Mul 1 2 3.0f 4.0f //Gives NO type error.