Как сделать функцию настолько полиморфной, чтобы она принимала произвольное количество произвольных аргументов?
Понятно, что можно взять обобщённый список и подать его как единственный аргумент
{-# LANGUAGE ExistentialQuantification, GADTs #-}data S = forall a . Show a => S a
join :: [S] -> String
join = (foldr (\x y -> x ++ ";" ++ y) "") . (map (\(S x) -> show x))
main = putStrLn $ join [S 1, S "2", S (), S ["hello","world"]]
Здравствуйте, deniok, Вы писали:
D>Надо добавить тип для magic
То есть, без этой аннотации компилятор считает, что prc "" имеет тип String, потому что... почему?
Потому что между типами String и String->xz (оба из которых подходят под класс VarArgs) он сперва выберет то, где нет переменных типа, — а уже потом налетит на оператор пробел в выражении (f 1)?
И это касается только констант верхнего уровня?
Ведь стоит написать
shmagic _ = prc ""
figagic = const $ prc ""-- казалось бы, то же, что и выше, но фиг!
main = do
useMagic (prc "")
useMagic (shmagic 0)
useMagic (figagic 0) -- нихьт компилирен
Вывод типов в системах высших рангов — неразрешимая задача, а мы там оказались, включив расширение RankNTypes. Поэтому по умолчанию стоит аннотировать типами все, что используется. Имеющийся алгоритм вывода кое-где позволяет опускать явное приписывание, но, если с этим не работать все время, то все равно все случаи и подслучаи вылетают из головы.
Здравствуйте, deniok, Вы писали:
D>Надо добавить тип для shmagic и figagic
IdeOne считает, что shmagic (равно как и копипасты выражений из magic и figagic по месту использования) прекрасно обходится без аннотации.
В отличие от глобальных значений magic и figagic.
Вот это и смущает.
D>Вывод типов в системах высших рангов — неразрешимая задача, а мы там оказались, включив расширение RankNTypes. Поэтому по умолчанию стоит аннотировать типами все, что используется. Имеющийся алгоритм вывода кое-где позволяет опускать явное приписывание, но, если с этим не работать все время, то все равно все случаи и подслучаи вылетают из головы.
На самом деле, такие ситуации можно поймать на ровном месте в гораздо более простых условиях. http://ideone.com/jy5ibg
one _ = 1
two _ = 2
tri _ = 3 :: Int
fur _ = 4.0
one0 = one 0
two0 = two 0
tri0 = tri 0
fur0 = fur 0
pst :: Show t => t -> IO() -- без аннотации это сломает компиляцию функции ps !!!
pst = putStrLn . show
ps t = (putStrLn . show) t -- а здесь аннотация не нужна
main = do
ps $ one0 + tri0 -- чтобы компилировалось, надо константы заменить на выражения one 0, two 0
ps $ two0 + fur0
ps $ one0 + two0
Здравствуйте, deniok, Вы писали:
К>>Безо всяких высших рангов :\
D>А здесь бесточечный стиль, поэтому тоже требуется аннотация. Если добавить аргумент слева и справа — должен вывести.
Хотелось бы понять такую простую вещь.
Вот у нас есть константы
one = 1 -- неявно Num t => t, тип будет выведен позднее, по месту использования
two = 2
one' :: Num t => t -- с такой аннотацией получили полиморфную константу, куда хочешь, туда и подставляешь
one' = 1
two' :: Num t => t
two' = 2
sss = show -- неявно Show t => t -> String, аннотация нужна прямо здесь и сейчас (даже если не используется)
sss' :: Show t => t -> String
sss' = show
К>pst :: Show t => t -> IO() -- без аннотации это сломает компиляцию функции ps !!!
К>pst = putStrLn . show
К>ps t = (putStrLn . show) t -- а здесь аннотация не нужна
К>
К>Безо всяких высших рангов :\
Вспомнил откуда ноги растут! Тут надо добавить прагму NoMonomorphismRestriction и все скомпилируется без аннотации. (Эту прагму, вообще, надо повсюду добавлять, Monomorphism Restriction не нужен.)