Проблема декомпозиции списка SML - PullRequest
0 голосов
/ 29 марта 2020

Я нашел старый курс U of Washington CSE341: Языки программирования и пытаюсь следовать ему, чтобы однажды справиться с ML Полсона для работающего программиста . Итак, у меня есть это:

fun number_in_month5 (m : int, ms : (int*int*int) list) =
    List.length (List.filter (fn (_,x2,_) => x2 = m) ms)

, который возвращает мне список подходящих 3-х кортежей. Я могу бросить List.length на фронт и получить счет. Но что по этому поводу

fun number_in_month6 (m, (_,d2,_) :: ms) =
    List.length (List.filter (fn (_,x2,_) => x2 = m) ms)

: stdIn:279.36 Warning: calling polyEqual
: stdIn:278.5-279.43 Warning: match nonexhaustive
:           (m,(_,d2,_) :: ms) => ...
:   
: val number_in_month6 = fn : ''a * ('b * ''a * 'c) list -> ('b * ''a * 'c) list

Тестирование иногда дает неверные ответы

- number_in_month6  (2,[(2018,2,1),(2018,2,2),(2018,1,3),(2018,2,4)])
val it = 2 : int

Почему это не работает? Но тогда я не умею читать сообщения об ошибках ML. Кто-то посоветовал не объявлять типы в начале функции - и я пытался, но мне это не удалось. Затем я нашел это

fun sumlists [] [] : int list = []
    |   sumlists (n :: ns) (m :: ms) = (n + m) :: sumlists ns ms;

    ;;; ML WARNING - Clauses of function declaration are non-exhaustive
    ;;; CONTEXT  :  fun sumlists
    val sumlists = fn : int list -> int list -> int list

Определение оставляет выражение, такое как sumlists [1] []; undefined.

Так что я понимаю концепцию неисчерпывающего, но я могу Не понимаю, почему моя функция не является исчерпывающей и дает плохие ответы.

1 Ответ

2 голосов
/ 29 марта 2020
fun number_in_month6 (m, (_,d2,_) :: ms) =
List.length (List.filter (fn (_,x2,_) => x2 = m) ms)

: stdIn:279.36 Warning: calling polyEqual
: stdIn:278.5-279.43 Warning: match nonexhaustive
:           (m,(_,d2,_) :: ms) => ...
:   
: val number_in_month6 = fn : ''a * ('b * ''a * 'c) list -> ('b * ''a * 'c) list

Я не могу понять, почему моя функция не является исчерпывающей и дает неверные ответы.

  • Не исчерпывающая: существует значение, которое шаблон (_,d2,_) :: ms не будет совпадать, то есть []. Кажется, проблема в том, что вы сопоставляете шаблон на входе number_in_month6 вообще, когда вам действительно нужно сделать это только внутри функции предиката для List.filter.

    Возможно, здесь неверное представление о том, что «вход не будет списком из трех кортежей, если я не сопоставлю шаблон в аргументе, так как я удалил аннотации типов ". Может быть интересно знать, что типовой вывод SML достаточно силен, чтобы сделать вывод, что ms является списком из трех кортежей, просто используя List.filter и fn (_,month2,_) => ....

  • Bad ответы: иногда результат равен единице, потому что вы отбрасываете первый элемент, (_,d2,_), и видите, какова длина отфильтрованного остатка списка, ms.

    В вашем примере первая дата предполагается, что он считается частью правильного результата, 3, но вместо этого он отбрасывается, а оставшиеся 2 из 3 дат учитываются правильно.

Исправление:

fun number_in_month (month1, dates) =
    List.length (List.filter (fn (_, month2, _) => month1 = month2) dates)

И тестирование этого:

- number_in_month6 (2,[(2018,2,1),(2018,2,2),(2018,1,3),(2018,2,4)]);
> val it = 3 : int

Некоторые моменты: Если вы называете переменные более точные имена, вам легче понять, что происходит. Вы можете рассмотреть возможность использования записи вместо кортежа. Они в основном одинаковы, за исключением того, что кортежи имеют пронумерованные записи, а записи имеют именованные записи, а синтаксис записей немного сложнее. Но положительным моментом является то, что вы случайно не забудете американские, европейские или ISO даты:

type date = { year : int, month : int, day : int }

fun number_in_month (month1, dates : date list) =
    List.length (List.filter (fn ({ month = month2, ... }) => month1 = month2) dates)

val test_1 = number_in_month (2, [ { year = 2018, month = 2, day = 1 }
                                 , { year = 2018, month = 2, day = 2 }
                                 , { year = 2018, month = 1, day = 3 }
                                 , { year = 2018, month = 2, day = 4 }
                                 ])

Синтаксис записи может быть немного сложным, так что не стесняйтесь продолжать с кортежами так долго как вы находите их практичными.

...