Использование альтернативных прелюдий в haskell - PullRequest
2 голосов
/ 14 марта 2019

Меня интересуют альтернативные прелюдии.Я понимаю, что есть много вариантов:

  1. https://hackage.haskell.org/packages/#cat:Prelude
  2. https://guide.aelve.com/haskell/alternative-preludes-zr69k1hc

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

Однако, когда я пытаюсь использовать эти альтернативы, поведение в head, хм, кажется просто нарушаетсяфункция полностью, и не выглядит как улучшение для меня.Вот несколько примеров:

Прелюдия

Prelude> head [1]
1
Prelude> head []
*** Exception: Prelude.head: empty list

Основание

Foundation> head [1]

<interactive>:6:6: error:
    • Couldn't match expected type ‘NonEmpty c’
                  with actual type ‘[Integer]’
    • In the first argument of ‘head’, namely ‘[1]’
      In the expression: head [1]
      In an equation for ‘it’: it = head [1]
    • Relevant bindings include
        it :: foundation-0.0.21:Foundation.Collection.Element.Element c
          (bound at <interactive>:6:1)
Foundation> head []

<interactive>:7:6: error:
    • Couldn't match expected type ‘NonEmpty c’ with actual type ‘[a0]’
    • In the first argument of ‘head’, namely ‘[]’
      In the expression: head []
      In an equation for ‘it’: it = head []
    • Relevant bindings include
        it :: foundation-0.0.21:Foundation.Collection.Element.Element c
          (bound at <interactive>:7:1)

Сейф

Safe> head []

<interactive>:22:1: error: Variable not in scope: head :: [a0] -> t

Классная прелюдия

ClassyPrelude> head [1]

<interactive>:24:6: error:
    • Couldn't match expected type ‘NonNull mono’
                  with actual type ‘[Integer]’
    • In the first argument of ‘head’, namely ‘[1]’
      In the expression: head [1]
      In an equation for ‘it’: it = head [1]
    • Relevant bindings include
        it :: Element mono (bound at <interactive>:24:1)

Relude

Relude> head [1]

<interactive>:27:6: error:
    • Couldn't match expected type ‘NonEmpty a’
                  with actual type ‘[Integer]’
    • In the first argument of ‘head’, namely ‘[1]’
      In the expression: head [1]
      In an equation for ‘it’: it = head [1]
    • Relevant bindings include it :: a (bound at <interactive>:27:1)

Rio

RIO> head [1]

<interactive>:7:1: error:
    Variable not in scope: head :: [Integer] -> t

Protolude

Protolude> head [1]
Just 1
Protolude> head []
Nothing

Это выглядит хорошо --- это также работает для хвоста, верно?

Protolude> tail [1]

<interactive>:12:1: error:
    • Variable not in scope: tail :: [Integer] -> t
    • Perhaps you meant ‘tails’ (imported from Protolude)

Protolude> tails [1]
[[1],[]]

Protolude> tails []
[[]]

Ну, это не полная замена.

Чего мне не хватает, почему это лучше, почему эти функции были определены, если они просто потерпят неудачу?

1 Ответ

9 голосов
/ 14 марта 2019

В большинстве случаев они вводятся, потому что они терпят неудачу во время компиляции, а не во время выполнения.

Проблема с Prelude.head не в том, что он может потерпеть неудачу.Дело в том, что имеет , поскольку нет способа взять список [a] и всегда создать элемент a, поскольку входной список может быть пустым.Не существует простого исправления, которое является заменой для замены, необходимо радикальное изменение.

Более безопасная и, возможно, лучшая прелюдия может решить эту проблему одним из следующих способов:

  • удалить head, чтобы программист не использовал опасный инструмент.Любое использование head завершится неудачно во время компиляции.Не очень, но все в порядке.

  • ограничивают тип ввода, например, head :: NonEmptyList a -> a.Это будет полезно, но программист должен адаптировать код так, чтобы гарантировать, что список ввода действительно не пуст.Простая передача непустого списка не подойдет для компилятора - компилятор хочет доказательства , и это правильно.Хорошие новости заключаются в том, что предыдущий код будет завален ошибками компиляции, что поможет программисту определить части программы, которые необходимо исправить.

  • ограничьте тип вывода, например, head :: [a] -> Maybe a.Это можно использовать просто отлично, но программист должен будет справиться с другим типом результата и обработать все потенциальные Nothing с.Опять же, ошибки времени компиляции помогут программисту определить, где нужно исправить некоторые ошибки.

В любом случае программист должен изменить код.Там нет никакого способа обойти это.Однако после устранения ошибок времени компиляции программа гарантированно никогда не выдаст head: empty list ошибок во время выполнения.

...