我正在尝试使用无点List.fold
函数重新发明List.reduce
,List.sum
和inline
以便学习。这就是我所拥有的:
let flip f y x = f x y
let rec fold folder seed = function
| [] -> seed
| h :: t -> fold folder (folder seed h) t
let inline reduce< ^a when ^a : (static member Zero : ^a) > :
(^a -> ^a -> ^a) -> ^a list -> ^a =
flip fold LanguagePrimitives.GenericZero
let inline sum< ^a when
^a : (static member (+) : ^a * ^a -> ^a) and
^a : (static member Zero : ^a)> : ^a list -> ^a =
reduce (+)
// ^ Compile error here
我知道在F#中不经常使用这种冗长的类型限制,但我正在努力学习,请耐心等待。
我有一个非常神秘的编译错误,我不明白:
Type mismatch. Expecting a
'a -> 'a -> 'a
but given a
'a -> 'b -> 'c
A type parameter is missing a constraint 'when ( ^a or ^?269978) : (static member ( + ) : ^a * ^?269978 -> ^?269979)'
A type parameter is missing a constraint 'when ( ^a or ^?269978) : (static member ( + ) : ^a * ^?269978 -> ^?269979)'
val ( + ) : x:'T1 -> y:'T2 -> 'T3 (requires member ( + ))
Full name: Microsoft.FSharp.Core.Operators.( + )
Overloaded addition operator
x: The first parameter.
y: The second parameter.
我应该添加什么来满足编译器?
答案 0 :(得分:3)
我不知道如何按照您的意愿完成任务,因为我无法以无点样式调用静态约束的静态成员。请注意,您没有调用(+)
^a
并且编译器不知道如何解决这个问题...如果您对使用内部帮助函数感到满意,您可以这样做:
let inline sum< ^a
when ^a : (static member (+) : ^a -> ^a -> ^a) and
^a : (static member Zero : ^a) > : ^a list -> ^a =
let add x y = (^a : (static member (+) : ^a -> ^a -> ^a) (x, y))
reduce add
注意警告
警告FS0077:F#编译器赋予名称为“op_Addition”的成员约束特殊状态,因为某些.NET类型会被此成员隐式扩充。如果您尝试从自己的代码中调用成员约束,这可能会导致运行时失败。
确实:
sum [1; 2; 3]
导致
System.NotSupportedException:不支持指定的方法 在FSI_0005.it@15-1 .Invoke(Int32 x,Int32 y)in ...
但是如果您将sum
更改为:
let inline sum list =
reduce (+) list
sum [1; 2; 3] // 6
答案 1 :(得分:3)
我无益的答案是:不要这样做。内联定义仅用于语法功能,因此您不应该以无点的方式定义它们。例如,比较尝试评估以下三行的结果:
let inline identity = id
let inline identity : ^a -> ^a = id
let inline identity< ^a> : ^a -> ^a = id
只有最后一个编译,(技术上这是因为它&#39;类型函数&#34;,这基本上是一个函数,它传递了隐藏的unit
后面的值允许将其视为通用值的场景。)
然而,如果你坚持以这种方式做事,那么一种方法来解决问题。这是使(+)
不那么通用;默认情况下,参数和返回类型可以是不同的类型,这种灵活性引入的约束是令编译器混淆的一部分。这是一个修复:
let inline reduce< ^a, 'b when ^a : (static member Zero : ^a)> : ( ^a -> 'b -> ^a) -> ('b list -> ^a) =
flip fold LanguagePrimitives.GenericZero
let inline (+) (x:^a) (y:^a) = x + y
let inline sum< ^a
when ^a : (static member ( + ) : ^a * ^a -> ^a)
and ^a : (static member Zero : ^a)> : ^a list -> ^a =
reduce (+)
答案 2 :(得分:1)
与Vandroiy一样,给定的reduce函数不会为我编译。我认为你想要的reduce
功能实际上是:
let inline reduce< ^a when ^a : (static member Zero : ^a) > : ((^a -> ^a -> ^a) -> ^a list -> ^a) =
flip fold LanguagePrimitives.GenericZero
这样做我能够复制你给出的错误。
但是,当我使用简单的测试函数更改sum
函数进行编译时:
let inline sum< ^a when
^a : (static member Zero : ^a) and
^a : (static member (+) : (^a -> ^a -> ^a)) > : ^a list -> ^a =
reduce (fun i j -> i)
并尝试致电sum [1..10]
会导致The type 'int' does not support the operator 'get_op_Addition'
。因此,我不确定这种方法是否有效。
编辑:感谢CaringDev的提示,我修复了get_op_Addition错误。这似乎有效。虽然至于为什么,我感到非常困惑,因为'b
只是^a
伪装......
let inline sum< ^a when
^a : (static member Zero : ^a) and
^a : (static member (+) : ^a -> ^a -> ^a) > : ^a list -> ^a =
let inline add (x:'b) (y:'b) = (+) x y
reduce add