2009-04-26 3 views
1

Ich machte eine Übung auf F# Wiki Book on List (scrollen Sie nach unten), um eine Pair Methode zu erstellen.Wie erstellt man eine "Pair" -Funktion, die mit einer String-Liste übereinstimmt?

Ich konnte eine Integer-Liste ohne Probleme paaren, aber eine F # Ausnahme wurde für eine String-Liste geworfen. Es ist einfach zu kryptisch für mich zu entziffern, was die Ausnahme für einen F # Anfänger wie mich bedeutet.

Hier ist mein erster Versuch zur Umsetzung Pair auf fsi.exe

> let pair l = 
-  let rec loop acc = function 
-   | [] -> acc 
-   | (hd1 :: hd2 :: tl) -> loop ((hd1, hd2) :: acc) tl 
-  List.rev(loop [] l) 
- 
- printfn "%A" ([1..10] |> pair) 
- printfn "%A" ([ "one"; "two"; "three"; "four"; "five" ] |> pair);; 

     let rec loop acc = function 
    -----------------------^ 

stdin(2,24): warning FS0025: Incomplete pattern matches on this expression. 
    For example, the value '[_]' will not be matched 

val pair : 'a list -> ('a * 'a) list 

[(1, 2); (3, 4); (5, 6); (7, 8); (9, 10)] 
Microsoft.FSharp.Core.MatchFailureException: 
Exception of type 'Microsoft.FSharp.Core.MatchFailureException' was thrown. 
    at [email protected](List`1 acc, List`1 _arg1) 
    at FSI_0002.pair[T](List`1 l) 
    at <StartupCode$FSI_0002>.$FSI_0002._main() 
stopped due to error 

So Pair funktioniert auf Integer-Version
und die Funktion Signatur

val pair : 'a list -> ('a * 'a) list 

zeigt an, dass Pair auf einer generischen Liste arbeitet.

Frage: Warum würde dann Pair nicht auf einer String-Liste arbeiten?

[ANTWORT] (meine Version)
einfach angehäuft Liste Rückkehr für else Fall (_) hat den Trick.
Und die Warnung ist auch erledigt.

let pair l = 
    let rec loop acc = function 
//  | [] -> acc 
     | (hd1 :: hd2 :: tl) -> loop ((hd1, hd2) :: acc) tl 
     | _ -> acc 
    List.rev(loop [] l) 

printfn "%A" ([1..10] |> pair) 
printfn "%A" ([ "one"; "two"; "three"; "four"; "five" ] |> pair) 

[EDIT 2] Nun, ich werde auch meine Version von Unpair auf Vollständigkeit stellen.

let unpair l = [for (a,b) in l do yield! a :: b :: []] 

Hier ist etwas fehlerhaft Benchmarking, dass unter Verwendung von Lösungs Version gegen Mine für 1 Million Itemlisten

#light 

open System; 

let pn l = printfn "%A" l 

let duration f = 
    let startTime = DateTime.Now; 
    let returnValue = f() 
    let endTime = DateTime.Now; 
    printfn "Duration (ms): %f" (endTime - startTime).TotalMilliseconds 
    returnValue 

let ll = [for a in 1..1000000 do yield (a)] 
let tl = [for a in 1..1000000 do yield (a,a)] 


let pair1 l = 
    let rec loop acc = function 
     | [] | [_] -> List.rev acc 
     | h1 :: h2 :: tl -> loop ((h1, h2) :: acc) tl 
    loop [] l 

let unpair1 l = 
    let rec loop acc = function 
     | [] -> List.rev acc 
     | (h1, h2) :: tl -> loop (h2 :: h1 :: acc) tl 
    loop [] l 

let pair2 l = 
    let rec loop acc = function 
     | (hd1 :: hd2 :: tl) -> loop ((hd1, hd2) :: acc) tl 
     | _ | [_] -> acc 
    List.rev(loop [] l) 

    let unpair2 l = [for (a,b) in l do yield! a :: b :: []] 

pn(duration (fun() -> ll |> pair1)) 
pn(duration (fun() -> tl |> unpair1)) 

pn(duration (fun() -> ll |> pair2)) 
pn(duration (fun() -> tl |> unpair2)) 

Benchmark Ergebnis:

Solution version 
PAIR -> Duration (ms): 255.000000 
UNPAIR -> Duration (ms): 840.000000 

My version 
PAIR -> Duration (ms): 220.000000 
UNPAIR -> Duration (ms): 1624.000000 
+0

Übrigens, Wiki-Buch listet eine Lösung für die Umsetzung "Pair", aber ich entschied mich, nicht zu betrügen. – Sung

Antwort

6

Ich glaube nicht, Ihre Version von Pair würde auf einer Liste einer ungeraden Anzahl von irgendetwas arbeiten. Sie testen zufällig eine gerade Anzahl von Ints und eine ungerade Anzahl von Strings. Ich denke, Ihr zweites Argument entspricht einer Liste von mindestens zwei Mitgliedern. Also breakst du 2 break off 2 und gehst zu einer Liste mit 1 element und keiner deiner bedingungen passt.

[_] ist eine 1-Item-Liste mit allem darin. Sie müssen ein Prädikat angeben, das diesem entspricht.

+0

Ich habe gerade zurückgegeben, was auch immer der akkumulierte Wert für "else" Fall zurückgegeben wird. Es klappt! Danke - Antwort ist in der Frage veröffentlicht. – Sung

Verwandte Themen