Кажется, не может использовать выражение типа с переменной типа в объявлении экземпляра с функцией, требующей явного типа - PullRequest
0 голосов
/ 15 апреля 2019

Я не могу найти в Хаскеле, чтобы указать тип вызова ' neg ':

instance Arith (V3 e) where neg x = vfmap (neg :: e->e)  x 

(V3 e) и e являются экземплярами Arith . Здесь я хочу вызвать ' neg ', уже определенный для типа 'e' . Но для этого требуется явный тип в вызове ' neg ', и никакое выражение не может разрешить тип? Если использовать конкретный экземпляр 'e' , это нормально.

vfmap (neg :: Dist->Dist ) x - это работает (но не достаточно широко) vfmap (neg :: e->e) x - Нет экземпляра для ( Arith e1 ), возникшего в результате использования ‘neg vfmap neg e - Неоднозначная переменная типа "e0", возникающая в результате использования "neg" предотвращает ограничение ‘(Arith e0)’. vfmap (neg :: Arith e => e->e) x - то же самое

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, InstanceSigs #-}
data Dist = Inch Float deriving (Show)

class Arith a where
   neg :: a->a

instance Arith Dist where
   neg (Inch x) = Inch (-x)

data V2 e = V2 e e    deriving (Show) 
data V3 e = V3 e e e  deriving (Show)

class VMap c e where
   vfmap :: (e->e)->c->c

instance VMap (V2 e) e where
   vfmap f (V2 x1 x2) = V2 (f x1) (f x2)
instance VMap (V3 e) e where
   vfmap f (V3 x1 x2 x3) = V3 (f x1) (f x2) (f x3)

-- 2 & 3 point vectors should also be Arith
instance Arith (V2 Dist) where 
   neg x = vfmap (neg :: Dist->Dist) x -- works, but must have type on neg

instance Arith (V3 e) where 
   neg x = vfmap (neg :: Arith e => e->e)  x -- nothing here seems to work

vfmap может применяться к ( V2 e ) или a ( V3 e ), любому типу вектора для вектора любого Arith тип элемента.

Это не скомпилируется, если тип элемента является переменной типа, например,

• Неопределенная переменная типа type e0 ’, возникающая из сигнатуры типа выражения предотвращает ограничение ‘ (Arith e0) ’. Возможное исправление: используйте аннотацию типа, чтобы указать, каким должно быть 10 e0 ’.

1 Ответ

5 голосов
/ 15 апреля 2019

Проблема в том, что в Haskell переменные типа не ограничены: то есть, если вы определяете instance Arith (V3 e), вы не можете использовать e внутри экземпляра; если вы попытаетесь это сделать, GHC интерпретирует его как совершенно отдельную переменную типа. К счастью, вы можете использовать {-# LANGUAGE ScopedTypeVariables #-} для включения переменных типа scoped. Если вы сделаете это, вы также обнаружите, что вам нужно добавить дополнительное ограничение Arith e =>; добавив это, вы сможете успешно скомпилировать.

(Кроме того: при работе с MultiParamTypeClasses, {-# LANGUAGE FunctionalDependencies #-} также невероятно полезен; я бы лично использовал его в таком случае, так как это устраняет необходимость явных объявлений типов для neg. Идея состоит в том, что вместо этого вы определяете class Functor c e | c -> e, что в основном означает, что тип для c также определяет тип для * 1012. * Я не буду описывать его здесь, но я бы весьма рекомендовал бы вам посмотреть его до.)

...