Почему эта реализация недействительна? - PullRequest
0 голосов
/ 22 октября 2018

Допустим, у меня есть следующая сигнатура типа:

someFunction :: (Eq a, Eq b) => a -> b

С реализацией:

someFunction x = (2 :: Int)

(Не смотрите на это слишком далеко, это всего лишь пример).

Насколько я понимаю, подпись такова, что "someFunction принимает аргумент, который является экземпляром класса типов Eq, и возвращает значение (которое может быть другого типа), которое является экземпляромEq класс типов ".Int является экземпляром Eq, так почему GHC расстраивается из-за этой реализации?

Ошибка делает это достаточно очевидным:

Couldn't match expected type ‘b’ with actual type ‘Int’
     ‘b’ is a rigid type variable bound by
       the type signature for:
         someFunction :: forall a b. (Eq a, Eq b) => a -> b

Iугадайте, что я не понимаю, это требование, чтобы оно работало "forall" b.Любой код, использующий эту функцию, должен опираться только на тот факт, что b является экземпляром Eq, верно?В моей голове реализация действительно соответствует подписи.А как насчет моей реализации нарушает ожидания этой подписи?

1 Ответ

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

Нет, ваша подпись типа, которая на самом деле

forall a b. (Eq a, Eq b) => a -> b

означает, что ваша функция должна вызываться с любыми типами a и b, как определено call site , если оба являются экземплярами Eq.

Не ваша функция решает, какой тип вернуть. Это использование вашей функции , который определяет это.

Таким образом, вы должны иметь возможность написать

    let { i :: Int; i = 1;
          n :: Integer; y :: Double;
          n = foo i;   -- foo :: Int -> Integer
          y = foo i    -- foo :: Int -> Double
        }

, и, как вы можете видеть, единственная реализация для вашей функции - это нет реализация:

foo _ = x where {x = x}

, потому что у вас нет возможности получить значение любого типа , которое от вас требуется.Этот тип может быть любым, и вы ничего не можете о нем знать.


Кстати, другие классы типов могут фактически позволить вам определить что-то здесь, как

foo :: (Enum a, Enum b, Bounded a, Bounded b) => a -> b 
foo a = snd . last $ zip [minBound .. a] (cycle [minBound ..])

Я не говорю, что это разумное определение, просто оно возможно:

> foo () :: Bool
False

> foo True :: Int
-9223372036854775807

> foo (0 :: Int) :: Bool
Interrupted.

Это, вероятно, распространенное заблуждение для программистов, исходящих из более привычныхЯ думаю, что foo :: (Eq a) => a означает «я могу определить foo, чтобы вернуть любой тип, который я хочу, до тех пор, пока он находится в Eq».Это не так.:)

...