2014-09-27 3 views
1

Я определил следующие типы данных:Как использовать класс типа в полиморфный тип данных?

type MySet a = (a -> Bool) 

Я хочу, чтобы использовать его, чтобы определить набор функций, которые имеют следующее свойство: Для всех е в FUNC3, е 3 == 2.

func3 :: MySet (Eq a => a -> a) 
func3 = (\x -> (x 3) == 2) 

возникает следующая ошибка:

Illegal polymorphic or qualified type: Eq a => a -> a 
Perhaps you intended to use -XLiberalTypeSynonyms 
In the type signature for `func3': func3 :: MySet (Eq a => a -> a) 

Если я не использую класс типов Eq, я получаю эту ошибку вместо того, чтобы:

No instance for (Eq a) arising from a use of `==' 
Possible fix: 
    add (Eq a) to the context of 
    the type signature for func3 :: MySet (a -> a) 
+2

Попробуйте это 'func3 :: (Num a, Eq a) => MySet (a -> a)' –

+0

Это сработало! Благодаря! – marlanbar

ответ

5

Часто первый шаг к разработке проблемы с участием синонимов типа (вещи, которые выглядят как type ... = ...), чтобы пройти через вручную заменить синоним (левую часть выражения type) с расширением (правая рука боковая сторона). Итак:

func3 :: MySet (Eq a => a -> a) 

становится:

func4 :: (Eq a => a -> a) -> Bool 

Теперь GHC дает нам более полезную ошибку:

Illegal polymorphic or qualified type: Eq a => a -> a 
Perhaps you intended to use RankNTypes or Rank2Types 
In an expression type signature: (Eq a => a -> a) -> Bool 

RankNTypes это весело расширение, но это не очень полезно здесь. (Я объясню в одно мгновение).

As n.m. указал, что вы, вероятно, хотите сделать, это просто переместить ограничения из скобок:

func5 :: Eq a => (a -> a) -> Bool 

И тогда GHC позволяет вам знать, вы также должны Num. Кроме этого, мы имеем совершенно обычную подпись типа: ограничение до =>, а затем обычные переменные типа и определенный тип. Это хорошо; мы обычно хотим, чтобы типы были максимально простыми (но не более).

Но давайте создадим резервную копию и рассмотрим две вещи: введите синонимы и RankNTypes.

Во-первых, вы назвали MySet «типом данных». Это опасный способ подумать об этом. На самом деле это синоним , что означает, что это звучит так: MySet (a -> a) и (a -> a) -> Bool являются буквально синонимами; они означают одно и то же. Контраст примерно data MySetD a = MySetD (a -> Bool). Там MySetD на самом деле является типом данных типа «честный к Богу», который не может заменить, волей-неволей, для (a -> Bool) и наоборот.

Второй: что случилось с RankNTypes? Если мы обратимся, что расширение, мы могли бы написать это:

funcRN :: (forall a. (Eq a, Num a) => a -> a) -> Bool 
funcRN = (\x -> (x 3) == 2) 

И это то, что вы хотите с вещами как funcRN ((+) 1). Но как насчет этого?

g :: Int -> Int 
g x = x - 1 

funcRN g 

Это не работает.funcRN требует в качестве аргумента функции, которая может принимать любой тип a такой, что a является экземпляром Eq и Num. Это то, что означает бит forall a. (Eq a, Num a) =>. С g работает только с , Int, это неприемлемо для подписи funcRN.

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