2

の演算子オーバーロードを定義するレコード型で List.fold を使用しようとしていますが、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

オーバーロードは+うまく機能します

> jen + kevin;;
val it : int = 87

しかし、私が人のリストを持っているとしましょう:

> let people = [kevin;jen];;

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'

アキュムレータとして '0' を使用したため+、fold が暗黙的にリストを入力しているため、F# がこの方法で渡されたときのオーバーロードを識別できないことが問題であると推測しています。intカスタム オペレーターのオーバーロードを正しく機能させることができるかどうか、また可能であれば、それを実現するために何が欠けているかはわかりません。+(フロートで使用できるため、これを機能させることができると思います)。

編集

問題は型の不一致であることを理解しています。JaredPar が書いているように、ラムダを記述して 2 人の人物のレコードを取得し、年齢を追加できることがわかりました。それは私の主張ではありません。+問題は、私が既に書いた演算子のオーバーロードを有効なオーバーロードとしてフォールドによって認識されるようにする方法があるべきだと私には思われることです。

別の編集

ご意見をお寄せいただきありがとうございます。明らかになりつつあることの 1 つは、自分のやりたいことができないということですが、それは問題ありません。私は何かを学びました!私が見ているのは、演算子のオーバーロードの解決は、すべてのコンテキストで機能するとは限らないということです。そのため、ラムダとして渡されたものを、インフィックス ala として使用した場合と同じように機能させるシームレスな方法foldはありません。これが正しく機能しない理由は完全に理にかなっています。この問題を解決するために人々が提案した解決策は、基本的に特定の問題を処理するための 1 回限りのものです+jen + kevinfoldfoldbackなど) -- リストを操作するために、特別なケースのコードをたくさん書く必要はありませんでした。F# の演算子のオーバーロードの解決には、表面的なレベルまで動作させるいくつかの制限があることは明らかですが、これは問題ありません。

4

5 に答える 5

7

List.fold関数は型のラムダ/関数を取りますState -> T -> State。この場合の+演算子にはPerson -> Person -> int、署名と互換性のない型があります。これが、エラーが発生する理由です。

年齢を折りたたむには、次のことを試してください

people |> List.fold (fun sum p -> sum + p.Age) 0

ここでオペレーターを折り畳みの一部として使用する 1 つの方法は、 を Age プロパティ+にマップしてから、オペレーターに対して折り畳みを使用することです。 Personint +

people
|> Seq.ofList
|> Seq.map (fun p -> p.Age)
|> Seq.fold (+) 0
于 2012-01-10T01:44:19.423 に答える
4

これはあなたに役立つかもしれない合理的な解決策です。

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
于 2012-01-10T02:34:39.547 に答える
1

問題は、整数、浮動小数点数などを追加するために+が定義され、2人を追加するために+を定義することです..しかし、試してみると:

 List.fold (+) 0 people;;

あなたは int (0) を Person (people) に追加しようとしています!..

実際に2人を追加すると、これは整数を返します...そして、人を反復するたびに、蓄積(整数)と人(人のリスト)を取得します.....

今..オーバーロードやジェネリックを追加せずにこれを解決する簡単な方法を試してみてください:

[kevin;jen] |> List.fold (fun acc person -> acc + person.Age) 0

http://msdn.microsoft.com/en-us/library/dd233224.aspxの例と同様

let data = [("Cats",4);
        ("Dogs",5);
        ("Mice",3);
        ("Elephants",2)]
let count = List.fold (fun acc (nm,x) -> acc+x) 0 data
printfn "Total number of animals: %d" count

...

于 2012-01-21T15:06:15.823 に答える