В поисках Polyvariadic примеров функций, я нашел этот ресурс: StackOverflow: How to create a polyvariadic haskell function?, и был ответ фрагмент кода, как это:Haskell, polyvariadic функции и определение типа
class SumRes r where
sumOf :: Integer -> r
instance SumRes Integer where
sumOf = id
instance (Integral a, SumRes r) => SumRes (a -> r) where
sumOf x = sumOf . (x +) . toInteger
Тогда мы могли бы использовать:
*Main> sumOf 1 :: Integer
1
*Main> sumOf 1 4 7 10 :: Integer
22
*Main> sumOf 1 4 7 10 0 0 :: Integer
22
*Main> sumOf 1 4 7 10 2 5 8 22 :: Integer
59
Я попробовал изменить его немного, просто из любопытства, потому что я нашел, что это довольно сложно, на первый взгляд, и я попал в это:
class SumRes r where
sumOf :: Int -> r
instance SumRes Int where
sumOf = id
instance (SumRes r) => SumRes (Int -> r) where
sumOf x = sumOf . (x +)
Я только что изменил Integer
к Int
и превратили instance (Integral a, SumRes r) => SumRes (a -> r) where
менее полиморфный к instance (SumRes r) => SumRes (Int -> r) where
Чтобы скомпилировать его я должен был установить XFlexibleInstances
флаг. Когда я судимый испытать sumOf
функции У меня проблема:
*Main> sumOf 1 :: Int
1
*Main> sumOf 1 1 :: Int
<interactive>:9:9
No instance for (Num a0) arising from the literal `1'
The type variable `a0' is ambiguous...
Тогда я попробовал:
*Main> sumOf (1 :: Int) (1 :: Int) :: Int
2
Почему не Haskell сделать вывод, что мы хотим Int
в этой ситуации, учитывая, что мы используем Int
в пределах нашего SumRes
typeclass?
Похоже на дефолт (предполагается, что '1' означает, что' Int' 1) запускается после разрешения экземпляра в 'ghci'. Справедливо. Вы можете добавить отдельную группу экземпляров шага для «Integer» вместо «Int», и тогда у вас будет реальная двусмысленность. – pigworker
Вы можете прочитать [этот вопрос и мой ответ на него] (http://stackoverflow.com/q/10777283/791604) для некоторых объяснений в другом направлении и полезный трюк, который вы можете использовать для решения проблемы неверный вывод здесь: используйте 'instance a ~ Int => SumRes (a -> r)' вместо 'instance SumRes (Int -> r)'. –
Чтобы прояснить раздел о дефолте, 'Int' не является типом, для которого обычно используется значение по умолчанию, а' Integer'. Поэтому исходный код работает, по умолчанию все литералы «Integer». –