2015-01-22 4 views
0

Я немного в недоумении, почему последний рисунок в prodV в следующем не работает:возвращение типа GADT оценщика

{-# LANGUAGE GADTs #-} 

data V a where 
    V0 :: Float -> V Float 
    Vn :: [Float] -> V [Float] 

prodV :: (Num a) => V a -> V a -> a 
prodV (V0 x) (V0 y) = x * y 
-- prodV (Vn x) (Vn y) = zipWith (*) x y -- this one works 
prodV (Vn xs) (Vn ys) = [ sum $ zipWith (*) xs ys ] 
prodV (V0 n) (Vn ys) = map (* n) ys 

GHCi 7.8.3 жалуется:

Couldn't match type ‘Float’ with ‘[Float]’ 
Inaccessible code in 
    a pattern with constructor 
    Vn :: [Float] -> V [Float], 
    in an equation for ‘prodV’ 
In the pattern: Vn ys` 

Любые указатели? заранее заблаговременно

+0

С одной стороны, вы ожидаете, что ваша функция 'prodV' будет работать для всех типов' Num', но конструкторы 'V0' и' Vn' специально содержат 'Float'. Во-вторых, вы говорите, что 'a' в' V a' должен быть 'Num', но' Num a => [a] 'не является экземпляром' Num'. Похоже, вы приближаетесь к этой проблеме неправильно. – bheklilr

+2

Вы, безусловно, можете написать функцию типа 'unV :: V a -> a', которая просто разворачивает конструкторы, но предпосылка вашей функции неверна. Возможно, вам стоит рассмотреть 'Vn :: [Float] -> V Float', но это сделало бы' unV :: V a -> a' невозможным, если вы не конвертируете свой список 'Float' в один' Float' в некоторых мода в первую очередь. – bheklilr

+0

ошибка сохраняется, даже если я удалю ограничение Num; Я не совсем понимаю, почему конструкторы V0 и Vn не могут быть «смешанными». – ocramz

ответ

2

Подпись

prodV :: (Num a) => V a -> V a -> a 

предписывает, что оба аргумента имеют один и тот же параметр типа, но если вы подходите на V0 и Vn аргументы будут иметь типы V Float и V [Float], в котором параметр типа не соответствует ,

Я не совсем уверен, что вы хотите семантику быть, но я предполагаю, что вы хотите, чтобы определить GADT как нечто вроде

data V n where 
    V0 :: n -> V n 
    Vn :: [n] -> V n 

и вашей функции либо как

prodV :: (Num a) => V a -> V a -> V a 
prodV (V0 x) (V0 y) = V0 $ x * y 
prodV (Vn xs) (Vn ys) = Vn $ zipWith (*) xs ys 
prodV (V0 n) (Vn ys) = Vn $ map (* n) ys 

или, возможно,

prodV' :: (Num a) => V a -> V a -> a 
prodV' (V0 x) (V0 y) = x * y 
prodV' (Vn xs) (Vn ys) = sum $ zipWith (*) xs ys 
prodV' (V0 n) (Vn ys) = sum $ map (* n) ys 

Можете ли вы описать, что вы хотели бы функцию prodV на самом деле делать? Типы в вашем исходном коде не имеют для меня никакого смысла, как они есть.

2

Ну, GHC расскажет вам, в чем проблема. Из вашего определения V0 something всегда имеет тип V Floatsomething должен быть типа Float - но это не имеет значения здесь), в то время как Vn anything всегда имеет тип V [Float]. Но подпись типа для prodV указывает, что оба имеют один и тот же тип V a. Таким образом, в этом случае a должен быть Float и [Float] в то же время, что невозможно.

0

Я просто пытался понять, как перегружать функции, чтобы имитировать алгебраическую стенографию, но я думаю, что это не правильный путь. Каким будет идиоматический способ Хаскелла? Например. от Numeric.Matrix:

adaptScalar f1 f2 f3 x y 
    | dim x == 1 = f1 ([email protected]>0) y 
    | dim y == 1 = f3 x ([email protected]>0) 
    | otherwise = f2 x y 

instance Num (Vector Float) where 
    (+) = adaptScalar addConstant add (flip addConstant) 
    negate = scale (-1) 
    (*) = adaptScalar scale mul (flip scale) 
    signum = vectorMapF Sign 
    abs = vectorMapF Abs 
    fromInteger = fromList . return . fromInteger 

выбирает правильную реализацию оператора (например, + или *) в соответствии с размерностью операндов.

+0

Отправка ответа на свой вопрос не является хорошим способом обновления вопроса. Или задайте новый вопрос или отредактируйте оригинал. – user2407038

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