Как создать функцию «Pair» для сопоставления со списком строк? - PullRequest
1 голос
/ 27 апреля 2009

Я выполнял упражнение на F # Wiki Book on List (прокрутите вниз), чтобы создать Pair метод.

Мне удалось без проблем составить список целых чисел, но для списка строк было сгенерировано исключение F #. Для меня слишком загадочно расшифровать, что означает исключение для новичка в F #, такого как я.

Вот моя первая попытка реализации Pair на 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 FSI_0002.clo@2T.Invoke(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

Так что Pair работает на целочисленной версии
и подпись функции

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

указывает, что Pair работает с общим списком.

Вопрос: Тогда почему бы Pair не работать со списком строк?

[ОТВЕТ] (моя версия)
Просто вернув накопленный список для else case (_), добились цели.
И предупреждение позаботится, а также.

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)

[EDIT2] Что ж, я также опубликую свою версию Unpair для полноты.

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

Вот несколько некорректный бенчмаркинг, использующий версию решения с моей версией для 1 миллиона списков элементов

#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))

Результат теста:

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

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

1 Ответ

6 голосов
/ 27 апреля 2009

Не думаю, что ваша версия Pair будет работать со списком нечетного числа чего-либо. Вам довелось проверить четное число целых и нечетное количество строк. Я думаю, что ваш второй аргумент для сопоставления подразумевает список как минимум из двух участников. Таким образом, вы разбиваете 2 на 2 и получаете список с 1 элементом, и ни одно из ваших условий не соответствует.

[_] - это список из 1 элементов, в котором есть все. Вы должны предоставить предикат, соответствующий ему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...