2015-08-25 3 views
5

Извините, что беспокоит вас этой простой проблемой. Я пытаюсь узнать, как работает расширение семейства типов. Когда я обманывал себя, я столкнулся с ошибкой, я не мог понять, почему.Ошибка семьи типа Haskell

class Foo a b c where 
    data T a b c :: * 

    f :: a -> T a b c 

    g :: T a b c -> b 

    h :: c -> a -> b 
    h c a = g $ f a 

Сообщение об ошибке:

Could not deduce (Foo a b c0) arising from a use of ‘g’ 
from the context (Foo a b c) 
    bound by the class declaration for ‘Foo’ 
    at DB/Internal/Typecast.hs:(17,1)-(25,19) 
The type variable ‘c0’ is ambiguous 
Relevant bindings include 
    a :: a (bound at DB/Internal/Typecast.hs:25:9) 
    h :: c -> a -> b (bound at DB/Internal/Typecast.hs:25:5) 
In the expression: g 
In the expression: g $ f a 
In an equation for ‘h’: h c a = g $ f a 

Я не понимаю, как это с неоднозначным в T a b c для g. Не может ли компилятор получить тип c от T a b c от f?

Я просто хочу, чтобы композит g . f

+0

Пожалуйста, исправьте отступ в вашем примере кода, то есть разместите свой фактический код. Проводка кода, отличного от того, что вы на самом деле используете, просто искажает реальную проблему. – Cubic

+1

«Разве компилятор не может получить тип' c' из 'T a b c'' f'? Да, но где 'f' получает свой' T a b c'? –

+0

@ DanielWagner Извините, я не думаю, что понимаю, как работает семейство. Разве не в T a b c в f и g, что я объявляю в объявлении экземпляра, используя ключевое слово данных? – Larry

ответ

4

Заметим, что в определении

h :: c -> a -> b 
h c a = g $ f a 

нет никаких ограничений, что f и g относятся к же например, что вы определяете h для. (И эта гибкость часто бывает полезно для определения экземпляров.)

От умозаключения типа, результат g ограничивается быть того же типа b, и аргумент f ограничивается быть типа a, но нет ничего говоря, что T a b c, переданный от одного к другому, использует тот же c!

Чтобы исправить это в этом случае, вы можете включить ScopedTypeVariables и сделать

h c a = g (f a :: T a b c) 

Обратите внимание, что это работает, потому что семьи данных являются «инъективными» (аргументы типа из семейства данных могут быть выведены из конечного типа). Если бы вы использовали тип, то даже это не сработало бы, так как тогда T a b c не обязательно определял бы c.

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