2017-05-24 1 views
3

Ich habe die folgende Art:Karte auf der Karte <'a, int>

type MultiSet<'a when 'a: comparison> = MSet of Map<'a, int> 

und ich möchte jetzt af Kartenfunktion für diese Art mit der Unterschrift erklären:

('a -> 'b) -> Multiset<'a> -> Multiset<'b> when 'a : comparison and 'b : comparison 

Ich habe versucht:

let map m ms = 
    match ms with 
    | MSet s -> MSet (Map.map (fun key value -> m key) s) 

Aber das es die Unterschrift hat:

('a -> int) -> Multiset<'a> -> Multiset<'a> when 'a : comparison 

Was ist falsch an meiner Implementierung, wenn ich die zuerst erwähnte Funktionssignatur haben möchte?

Antwort

5

Map.map Karten Werte, keine Schlüssel. Und das aus gutem Grund: Es kann nicht einfach die abgebildeten Tasten anstelle der ursprünglichen Tasten anschließen - sie passen vielleicht nicht zusammen. Verdammt, sie sind vielleicht nicht einmal einzigartig für alle Map.map weiß!

Wenn Sie eine Karte mit verschiedenen Schlüsseln konstruieren wollen, müssen Sie es nehmen müssen als Folge auseinander, wandeln es, dann eine andere konstruieren Map von ihm:

let map m (MSet s) = 
    MSet (Map.ofSeq <| seq { for KeyValue (key, value) in s -> m key, value }) 

Diese Implementierung hat Ihre erforderliche Unterschrift .

(Beachten Sie auch, wie Sie müssen match nicht tun, können Sie das Muster direkt in Parameterdeklaration enthalten)

Vorsicht, dass diese Implementierung tut nichts für die neuen Schlüssel Validierung: zum Beispiel, wenn sie erweisen sich als nicht eindeutig, einige Punkte werden verloren gehen. Ich überlasse das als Übung für den Leser.

+1

Dies ist eine gute Antwort. Beachten Sie, dass es sich auch lohnt, zu überlegen, was zu tun ist, wenn mehrere alte Schlüssel demselben neuen Schlüssel zugeordnet werden (sollten die Zählwerte addiert oder ein Fehler ausgelöst oder ein willkürlicher Wert beibehalten werden?) – kvb

+0

Dies ist ein guter Punkt. Aber ich wollte die Antwort nicht überladen, nur das unmittelbare Problem gelöst. –

+0

Große Antwort, vielen Dank. – Alexander