Поскольку Haskell лениво оценивается, почему этот код не работает? - PullRequest
0 голосов
/ 28 октября 2018
--defining function
safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x

--calling function
safeHead (4:5:3:[]:[])

Когда я вызываю safeHead с аргументом (4: 5: 3: []: []), шаблон только оценивает аргумент, чтобы определить, является ли он пустым или имеет голову.Поэтому, несмотря на бессмысленный бит «[]: []», он не должен выдавать ошибку, так как эта часть даже не оценивается.

Ответы [ 3 ]

0 голосов
/ 28 октября 2018

Это займет немного массажа, но иногда вы можете получить ghc на отложить ошибки типа, такие как эта, и дать вам ответ независимо.

-- defer.hs
safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x

n :: Int
n = []

nonsense :: [Int]
nonsense = (4 : 5 : 3 : n : [])

r :: Maybe Int
r = safeHead nonsense

Учитывая приведенный выше файл, если вы загружаете это в ghc или ghci, используя флаг -fdefer-type-errors ...

$ ghci -fdefer-type-errors defer.hs

defer.hs:6:5: warning: [-Wdeferred-type-errors]
    • Couldn't match expected type ‘Int’ with actual type ‘[a0]’
    • In the expression: []
      In an equation for ‘n’: n = []
  |
6 | n = []
  |     ^^

ghci> r
Just 4

ghci> nonsense !! 3
*** Exception: defer.hs:6:5: error:
    • Couldn't match expected type ‘Int’ with actual type ‘[a0]’
    • In the expression: []
      In an equation for ‘n’: n = []
(deferred type error)

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

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

0 голосов
/ 28 октября 2018

Каждый бит в программе на Haskell должен иметь тип. Аванс .

Термин (4:5:3:[]:[]) действительно имеет тип.

> :t safeHead (4:5:3:[]:[])
safeHead (4:5:3:[]:[]) :: Num [t] => Maybe [t]

> safeHead (4:5:3:[]:[])

<interactive>:10:1:
    No instance for (Num [t0]) arising from a use of `it'
    In a stmt of an interactive GHCi command: print it

Это просто экземпляр, который отсутствует.

> instance (Num a) => Num [a] where
    a + b = a
    a - b = a
    a * b = a
    abs a = a
    signum a = a
    fromInteger x = [fromInteger x]

> safeHead (4:5:3:[]:[])
Just [4]
it :: Num t => Maybe [t]

Числовые литералы - это полиморфные определения, а не конкретные значения;4 фактически читается как (fromInteger 4) :: Num a => a, и поэтому конкретный fromInteger выполняет свою конкретную работу в соответствии с конкретным типом, который он на самом деле имеет.Здесь, это

four :: Num t => Num [t]
four = fromInteger 4         -- according to our definition, it's
     = [fromInteger 4]

Оказывается, это не полная ерунда в конце концов.:)

0 голосов
/ 28 октября 2018

он не должен выдавать ошибку, так как эта часть даже не оценивается.

Тот факт, что она не оценивается, не имеет значения.Haskell является статически типизированным языком, и компилятор проверяет типы.Не нужно вычислять результат, чтобы проверить тип значения: тип ввода и вывода всех функций известен (хорошо рассчитан), а компилятор Haskell проверяет, что тип вывода одной функции совпадает с типом вводафункция, которая вызывается для обработки этого вывода.

Проверка типов выполняется в время компиляции , а компилятор Haskell не ленив (в том смысле, что он выполняетэти проверки перед генерацией двоичного файла, а не только перед запуском кода).Компилятор охотно проверяет типы и гарантирует, что программа чувствительна с точки зрения системы типов.

Например, следующее выражение будет проверять тип:

1 : 2 : undefined

, но undefined :: a вызовет ошибку в случае ее оценки.

Haskell позволяет определять новые типы Num bers, так что вы можете создать класс типов, который будет анализировать числа 4,5 и 3 на номера вашего собственного типа.Этот тип может быть, строго говоря, списком.

Но Haskell, если вы оцените это, не найдет тип для использования и выдаст ошибку:

Prelude> safeHead (4:5:3:[]:[])

<interactive>:6:1: error:
    • Non type-variable argument in the constraint: Num [t]
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        it :: forall t. Num [t] => Maybe [t]

Так что вот оноищет тип для элементов списка и обнаруживает, что это должны быть списки, из-за элемента [] (один, но последний элемент), но в то же время они должны быть Num s,теперь он не может найти такой тип, поэтому возникает ошибка.

Мы можем, строго говоря, создать такой тип, чтобы мы могли использовать функцию надлежащим образом:

Prelude> data A = A deriving Show
Prelude> :{
Prelude| instance Num [A] where
Prelude|     (+) = undefined
Prelude|     (*) = undefined
Prelude|     abs = undefined
Prelude|     fromInteger _ = [A]
Prelude|     negate = undefined
Prelude|     signum = undefined
Prelude| :}
Prelude> :{
Prelude| safeHead :: [a] -> Maybe a
Prelude| safeHead [] = Nothing
Prelude| safeHead (x:_) = Just x
Prelude| :}
Prelude> safeHead (4:5:3:[]:[]) :: Maybe [A]
Just [A]
...