2012-02-16 3 views
1

Я пытаюсь определить операции над списками с параметризованными параметрами. В конечном итоге у меня есть довольно много ограничений для этих списков (Map, Fold, что у вас есть), поэтому я хотел бы использовать новый GHC ConstraintKinds, чтобы немного упростить мою жизнь. Однако я не могу понять их.Какие функциональные зависимости задает этот размерный размер ZipWith, и почему?

Рассмотрим следующий (резко упрощенным) пример:

-- A list where length is implicit in the type. 
-- This allows us to have classes like 
-- Combineable a b c u v w | ... where 
-- combine :: (a -> b -> c) -> u -> v -> w 
-- which is a version of ZipWith that only works on 
-- lists of the same length. 
data a :. b = !a :. !b 

-- A simple class that works on our length-implicit lists 
class Fold v a | v -> a where 
    fold :: (a -> a -> a) -> v -> a 
instance Fold (a:.()) a where 
    fold f (a:._) = a 
instance Fold (a':.u) a => Fold (a:.a':.u) a where 
    fold f (a:.v) = f a (fold f v) 

-- A type constraint to simplify the constraints on our functions, 
-- which in the real world also contain a bunch of things like 
-- Map a a v v, Combineable a (Maybe a) (Maybe a) v w w, etc. 
type NList v i = (Fold (v i) i) 

-- A function that uses our type constraint 
foo :: (Num a, NList v a) -> v a -> a 
foo = fold (+) 1 

Выглядит довольно вменяемый мне. Правильно? Неправильно.

> foo ((1::Int) :.()) 

Couldn't match type `Int' with `()' 
When using functional dependencies to combine 
    Fold (a :.()) a, 
    arising from the dependency `v -> a' 
    in the instance declaration in `Data.Vec.Base' 
    Fold (Int :.())(), 
    arising from a use of `foo' at <interactive>:72:1-4 
In the expression: foo ((1 :: Int) :.()) 
In an equation for `it': it = foo ((1 :: Int) :.()) 

Для меня это сообщение об ошибке примерно переводится как «почему вы пытаетесь запрограммировать уровень типа?».

Очевидно, я не совсем понимаю последствия ограничений, но я не уверен, где я здесь ошибся. Может ли кто-нибудь обнаружить ошибку?

ответ

2

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

Вид v в

type NList v i = (Fold (v i) i) 

Кажется, конфликтовать с видом v в Fold

class Fold v a | v -> a where 
    fold :: (a -> a -> a) -> v -> a 

код работает для меня, если мы просто удалить определение NList и изменить foo к

foo :: (Num a, Fold v a) => v -> a 
foo = fold (+) 

(я также добавил декларацию фиксированности для :., чтобы получить правильную ассоциативность и добавил LANGUAGE прагм)

{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE FlexibleContexts #-} 
{-# LANGUAGE TypeOperators #-} 
{-# LANGUAGE FunctionalDependencies #-} 

data a :. b = !a :. !b 
infixr 5 :. 

Теперь мы можем запустить foo в GHCi

*Main> foo (1:.()) 
1 
*Main> foo (1:.2:.3:.()) 
6 
+0

Да. Проблема в том, что у меня есть целая куча ограничений, поэтому она больше напоминает '(Num a, Fold (va) a, Reverse '() (va) (va), Map aa (va) (va), Combineable aaa (va) (va) (va), Комбинируемый a (возможно, a) a (va) (v (Возможно, a)) (va)). Во-первых, это огромная боль, чтобы писать этот тип для каждой функции 'foo',' bar', 'baz' и т. Д. Иначе говоря, обратите внимание на последнее ограничение' Combineable': Вот почему мне нужно ввести 'v 'быть' * -> * ', так что я могу иногда манипулировать внутренним типом. – So8res

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

  • Нет связанных вопросов^_^