Почему недетерминированная функция выбора в std lib Карри определяется не напрямую, а с помощью вспомогательной функции с двумя аргументами? - PullRequest
15 голосов
/ 01 марта 2011

Рассмотрим функцию choose на языке программирования Curry со спецификацией, что "(choose xs) недетерминированно выбирает один элемент из списка xs".

.реализовать его напрямую через два альтернативных недетерминированных правила:

choose :: [a] -> a
choose x:_ = x
choose _:xs = choose xs

Но в /usr/lib/curry-0.9.11/Success.curry из Muenster Curry Compiler , он определенс помощью вспомогательной функции:

choose (x:xs) = choosep x xs
  where choosep x [] = x
        choosep x (_:_) = x
        choosep _ (x:xs) = choosep x xs

Какими могут быть преимущества (если таковые имеются) определения из поставляемого компилятором модуля?Являются ли эти 2 определения полностью эквивалентными (даже в некоторых сложных случаях с недетерминизмом и неопределенными значениями)? .. Является ли одно из них более эффективным в некоторых случаях?

ДОБАВЛЕНО: Более глубокое рассмотрение

cthom06(Спасибо!) Правильно указал, что мое определение вызовет попадание неопределенного значения в гораздо большее количество случаев (потому что мы будем пытаться вызывать эту функцию с аргументом пустого списка один раз для каждого нашего вызова «верхнего уровня» с изначально непустой список аргументов).(Хм, почему я не заметил это соображение сразу? ..) Это менее эффективно.

Но мне интересно: есть ли смысловые различия?Может ли разница быть важной в некоторых сложных контекстах?

Мы видим, что разница между двумя определениями - в случае непустых списков - в основном сводится к разнице между двумя потенциальными определениями для id:

мое определение похоже на определение id как:

id x = x
id _ = undefined

, а их определение похоже на определение id обычным образом:

id x = x

(Итак, здесь прямолинейность обращена вспять.)

В каких контекстах это может быть важно?

1 Ответ

2 голосов
/ 06 апреля 2011

Я полагаю, что нет семантических различий, но тот, который имеет вспомогательную функцию, более эффективен, особенно в общем случае (в определенных стилях программирования) списка с одним элементом. В этом случае избегается точка выбора, которую в вашей версии нужно будет настроить на рекурсивный вызов с [], который затем обязательно завершится неудачей.

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

...