2010-07-07 2 views
3

По-видимому, подпись моего типа отключена. С тех пор я узнал, почему. Теперь мне интересно узнать больше о предполагаемой подписи GHCI на моей опечатке. Я пытался заставить этот код работать:Haskell: В чем разница между `Num [a] => a` и` Num a => [a] `

elemNum :: (Eq a, Num b) => a -> [a] -> b 
elemNum e l = f e l 
    where f _ [] = [] -- this was my typo, supposed to read 0 
     f e (x:xs) 
      | x == e = 1 + f e xs 
      | otherwise = f e xs 

Он явно не работает по причине, указанной выше; но, если я удалю свою подпись компилирует (не знаю, почему, объясните, пожалуйста), и я получаю эту подпись:

elemNum :: (Num [a], Eq t) => t -> [t] -> [a] 

Я никогда не видел класс типов Num [a] перед тем .. Что это значит, и как делает он сравнивается с (Num a) => [a].

ответ

8

Num a означает, что тип a можно рассматривать как число; например. вы можете добавить два a s вместе, чтобы получить новый a, или вы можете отменить a и получить a. Integer и Double попадают в данную категорию.

Соответственно, Num [a] означает, что тип [a] можно рассматривать как номер. То есть вы можете добавить два списка из a, чтобы получить новый список a. Это вряд ли будет иметь смысл, потому что ни один из списков не является числом (по умолчанию). Это означает, что вы обрабатываете список, такой как номер, заставляя GHC заключить, что вы должны хотеть, чтобы ваш список действовал как число, и, таким образом, добавляя соответствующее ограничение.

Такое ограничение может возникнуть из функции, как:

foo (x:xs) = xs + 1 

xs является модель соответствует, как хвост списка, и, таким образом, сам список, а затем вы добавляете к нему, рассматривая список как число.

+1

Могу ли я сделать '[a]' членом 'Num', возможно ли, если да, можете ли вы представить простой пример? Если нет, почему бы и нет? –

+4

Да, вы могли бы. Например, если вы хотите предоставить многочлены, но это будет плохая идея в целом. экземпляр Num a => Num [a] где fromIntegral a = [a] (a: as) + (b: bs) = (a + b) :(as + bs) [] + bs = bs as + [] = as ... –

+3

Технически вы можете сделать что-либо экземпляром любого типа (при условии, что соответствующие виды), выполнив что-то вроде 'instance Num [a], где fromInteger x = undefined; x + y = undefined' и т. д. Очевидно, это было бы не полезно. –

2

Ограничение Num [a] означает, что список является экземпляром класса типа Num.

foo :: Num a => [a] 

является списком значений, которые являются экземплярами класса типов Num

bar :: Num [a] => [a] 

является списком значений, который является экземпляром класса типа Num самого по себе. Это означает, что вы можете использовать все функции из Num и создавать списки из числовых литералов так следующий код действителен, хотя требует FlexibleContexts

bar :: Num [a] => [a] 
bar = 42 

P.S. Здесь вам не нужна вспомогательная функция. elemNum e l = f e l ⇒ elemNum = f. Таким образом, вы можете написать свою функцию как

elemNum _ [] = 0 
elemNum e (x:xs) 
    | x == e = 1 + f e xs 
    | otherwise = f e xs 
Смежные вопросы