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.
Run Code Online (Sandbox Code Playgroud)
我想知道是否有办法让类型在上面的例子中做我想要的,或者我是否最终达到了F#类型系统的限制.实际上,有一种方法可以完成上述工作,即将所有类型放入一个DU,然后在DU类型上进行模式匹配,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
但假设第一个例子有效,那将是一个更加动态的解决方案.遗憾的是,在一个参数中通过名称传递一个更高阶的函数,并让它在现场内联以使其成为通用是不可能的.
大多数现代类型系统的这种限制在kvb对这个问题的回答中得到了很好的解释.
这是一个解决方法,基于那里建议的黑客.实际上它与你的代码非常相似,但不那么冗长.
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
Run Code Online (Sandbox Code Playgroud)
我们的想法是,不是定义一个函数,而是使用单个方法(您已经做过)定义一个类型,在这种情况下,它将是一个意味着应用的运算符.
所以不要做,f x你会写f $ x.
UPDATE
如前所述,您的代码与该答案中建议的解决方案相差不远.这是一个更接近原始代码的工作示例:
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.
Run Code Online (Sandbox Code Playgroud)
所以这基本上是你的原始代码,但使用静态方法并or在约束中使用.通过这样做,编译器不会提前解决约束,因此它可以工作.
我使用了运算符,因为它不那么冗长,在这种情况下我喜欢它的读取方式,因为Haskell $意味着函数应用.
| 归档时间: |
|
| 查看次数: |
108 次 |
| 最近记录: |