F#'+'运算符重载和List.fold

Kev*_*Won 2 f# overloading record fold operator-keyword

我正在尝试在定义运算符重载的记录类型上使用List.fold +,但是当尝试使用(+)运算符作为lambda传递给fold 时,我遇到类型不匹配错误.这是一个简化的代码片段,它举例说明了我的问题:

// a record type that also includes an overload for '+'
type Person = 
    { Name : string; Age: int }
    static member ( + ) (x: Person, y: Person) = x.Age + y.Age
Run Code Online (Sandbox Code Playgroud)

+超负荷的工作就好了

> jen + kevin;;
val it : int = 87
Run Code Online (Sandbox Code Playgroud)

但是说我有个人名单:

> let people = [kevin;jen];;
Run Code Online (Sandbox Code Playgroud)

我不能使用List.fold来总结所有年龄段:

> List.fold (+) 0 people;;

List.fold (+) 0 people;;
----------------^^^^^^

error FS0001: Type constraint mismatch. The type 
    int    
is not compatible with type
    Person    
The type 'int' is not compatible with the type 'Person'
Run Code Online (Sandbox Code Playgroud)

我猜测问题是F#无法识别+以这种方式传递时的重载,因为fold隐式输入列表,int因为我使用'0'作为累加器.我不确定是否有可能让我的自定义操作符重载正常工作,如果可能的话,我错过了让它发生的事情.(我假设它可以使这项工作,因为你可以使用+浮动).

编辑

我知道问题是类型不匹配.正如JaredPar所写,我知道我可以写一个lambda来获取两个人的记录并添加年龄.那不是我的观点.问题是在我看来应该有一种方法可以让+我已经编写的操作符重载被fold确认为有效的重载.

另一个编辑

谢谢大家的意见.有一件事情变得清晰,那就是不可能做我想做的事,但那没关系.我学到了什么!我所看到的是,运算符重载的解决方案使得它们不能在每个上下文中工作 - 因此fold没有无缝的方式可以+作为lambda工作传递,就像用作中缀ala时那样jen + kevin.总而言之,为什么这不起作用.人们建议解决这个问题的解决方案基本上是一次性处理特定问题 - fold我真正想到的是如何获得正确的运算符重载以获取每种情况(即foldback等等) - 我不想写一堆特殊的案例代码来处理列表.很明显不是F#的操作符重载分辨率有一些限制,使它适用于皮肤深层次,这很好.

Jar*_*Par 7

List.fold函数采用lambda /函数类型State -> T -> State.+在这种情况下,操作员的类型Person -> Person -> int与签名不兼容.这就是你收到错误的原因.

要折叠年龄,请尝试以下方法

people |> List.fold (fun sum p -> sum + p.Age) 0
Run Code Online (Sandbox Code Playgroud)

+此处使用运算符作为折叠的一部分的一种方法是Person将Age 映射到Age属性,然后对int +运算符使用fold .

people
|> Seq.ofList
|> Seq.map (fun p -> p.Age)
|> Seq.fold (+) 0
Run Code Online (Sandbox Code Playgroud)


Cha*_*ion 5

这是一个合理的解决方案,可能对您有用。

type Person = { 
    Name : string
    Age: int 
} with
    static member (+) (x: Person, y: Person) = 
        { Set = Set.ofList [x; y]; SumOfAges = x.Age + y.Age }

and People = { 
    Set:Person Set
    SumOfAges:int
} with
    static member (+) (x:People, y:Person) = 
        { x with Set = x.Set.Add y; SumOfAges = x.SumOfAges + y.Age }
    static member Empty = 
        { Set = Set.empty; SumOfAges = 0 }

let p = [ { Name = "Matt"; Age = 32; }; { Name = "Dan"; Age = 26; } ]
let r = p |> List.fold (+) People.Empty
Run Code Online (Sandbox Code Playgroud)