Избыточное совпадение типа данных SML обеспечивает избыточность - PullRequest
0 голосов
/ 07 мая 2020

У меня есть это Little MLer

datatype 'a pizza =
         Bottom
         | Topping of ('a * ('a pizza))

и это

datatype fish =
         Anchovy
         | Lox
       | Tuna

и этот рабочий код

fun rem_fish (f, fp) =
    let
        fun eq_fish (Anchovy,Anchovy) = true
          | eq_fish (Lox,Lox) = true
          | eq_fish (Tuna,Tuna) = true
          | eq_fish (_,_) = false
    in
        case fp of
            Bottom => Bottom
          | Topping(x,y) =>
            case eq_fish (f,x) of
                true => rem_fish (f,y)
              | false => Topping (x,rem_fish (f,y))
end

который возьмет тип fi sh и пару пиццы fi sh и удалит этот конкретный fi sh в первом аргументе

- rem_fish (Tuna, Topping (Tuna, (Topping (Anchovy, Topping (Lox, Topping (Tuna, Bottom))))));
Topping (Anchovy,Topping (Lox,Bottom)) : fish pizza

Хорошо, поэтому я вижу этот код (который у меня изменен на case на основе) помечен как "неграмотный"

fun rem_fish (f, fp) =
        case fp of
            Bottom => Bottom
          | Topping (f,fp') => rem_fish (f,fp')
          | Topping (x,fp') => Topping (x,rem_fish (f,fp'))

но эта ошибка

Error: match redundant
:           Bottom => ...
:           Topping (f,fp') => ...
:     -->   Topping (x,fp') => ...

Что означает эта ошибка? Что не так с кодом? Последняя строка могла быть примерно такой

Topping (_,fp') => Topping (?,rem_fish (f,fp'))

, но тогда я не знаю, что могло бы быть ?.

1 Ответ

1 голос
/ 08 мая 2020

Думаю, станет понятнее, если мы уберем из этого кода некоторые ненужные затенения. Рассмотрим функцию

fun rem_fish (f, fp) =
        case fp of
            Bottom => Bottom
          | Topping (y,fp') => rem_fish (y,fp')
          | Topping (x,fp') => Topping (x,rem_fish (f,fp'))

, которая эквивалентна тому, что вы написали.

Обратите внимание, что и Topping (y,fp'), и Topping (x,fp') являются неопровержимыми шаблонами для варианта Topping; они всегда будут соответствовать этому. Итак, в вашем коде, если у вас есть Topping, он всегда будет соответствовать второй ветке вашего case, и, таким образом, третья ветвь является избыточной (о чем говорит ошибка).

Если вы хотите иметь возможность проверить, равен ли первый элемент в кортеже, обернутом Topping, f, вам нужно либо явно сделать это с помощью op= (заставляя его быть типом равенства), либо взять какой-то функции равенства в качестве параметра для проверки (или иметь его внутри, как в начальном примере). Последний может выглядеть примерно как

fun rem_fish (_, Bottom) _ = Bottom
  | rem_fish (f, Topping (x, fp)) cmp = 
      if cmp (f, x) then
        rem_fish (f, fp)
      else
        Topping (x, rem_fish (f, fp))

(что может быть немного более общим для начинок, отличных от fi sh, которые имеют функции равенства)

...