2014-01-21 5 views
8

В Haskell можно определить функцию следующим образом:Добавление типа подписи причины ошибка компиляции

foo :: Int -> Int 
foo n = n + 1 

Если я хочу быть анальный, я могу добавить подпись типа до последней строки, как это:

foo :: Int -> Int 
foo n = n + 1 :: Int 

можно также определить функцию bar в терминах класса типа, как это:

class Rel a b where 
    aToB :: a -> b 

bar :: (Rel a b) => a -> b 
bar a = aToB a 

Однако, если я добавлю подпись типа к реализации bar (доброкачественное изменение, или так я думал), я получаю ошибку компиляции.

bar :: (Rel a b) => a -> b 
bar a = aToB a :: b 

А вот ошибка:

Could not deduce (Rel a b1) arising from a use of `aToB' 
from the context (Rel a b) 
    bound by the type signature for bar :: Rel a b => a -> b 
    at q.hs:79:1-23 
Possible fix: 
    add (Rel a b1) to the context of 
    an expression type signature: b1 
    or the type signature for bar :: Rel a b => a -> b 
In the expression: aToB val :: b 
In an equation for `bar': bar val = aToB val :: b 

Я думаю, что ошибка означает, что компилятор не убежден в том, что b в осуществлении bar является такой же, как b в тип подписи bar. Однако я не уверен, почему так будет.

Почему я получаю эту ошибку компиляции, когда добавляю подпись типа к моей реализации функции?

ответ

2

Ваша проблема заключается в объеме переменных типа. Когда вы пишете

bar :: (Rel a b) => a -> b 
bar a = aToB a :: b 

Первая строка (тип декларации для bar) имеет свою область применения для переменных типа, а на второй линии он видит :: b как другой б от Rel a b.

Если включить расширение ScopedTypeVariables и объявить тип, как

bar :: forall a b. (Rel a b) => a -> b 

Тогда b «s сфера распространяется на определение bar.

+0

Это имеет смысл. Есть ли причина, по которой расширение не может быть всегда включено? Или это похоже на классы с несколькими параметрами: явно хорошая идея, но только не на основном языке? – jcarpenter2

+0

Часто это хорошая идея, но это не Haskel98, поэтому это расширение. Я не сталкивался с ситуациями, когда проблема заключалась в том, что она была активирована лично, но другие могут более подробно рассказать о ней. – bheklilr

+2

Я спрашивал об этом несколько раз. Для моего нынешнего понимания это был просто недосмотр в Haskell98, и нет недостатка. –

6

Вы на самом деле нужно расширение языка и немного дополнительного синтаксис, чтобы сделать два b переменных типа быть одинаковым:

{-# LANGUAGE ScopedTypeVariables #-} 
bar :: forall a b . (Rel a b) => a -> b 
bar a = aToB a :: b 

forall, по существу говоря, "a и b должны находиться в области видимости для всей определение "и ScopedTypeVariables необходимо для использования этого синтаксиса.

Я думаю, что это действительно историческая бородавка в дизайне языка.

Смежные вопросы