Printf-подобная функция

Я пытаюсь написать функцию с произвольным числом аргументов. Эти аргументы могут быть Int или String. И у меня есть проблема с Ints. По какой-то причине (которую я не понимаю) значение 1 становится источником неоднозначности. Как бороться с этой ошибкой и каков ее источник?

{-# LANGUAGE FlexibleInstances #-}
import Data.Typeable

data PackArgTypes = PackInt Int | PackString String
                              deriving Show

class PackArg t where
  toPackArg :: t -> PackArgTypes

instance PackArg Int where
  toPackArg = PackInt . fromIntegral
instance PackArg Integer where
  toPackArg = PackInt . fromIntegral

instance PackArg String where
  toPackArg = PackString

class PackType t where
  pack' :: String -> [PackArgTypes] -> t

instance PackType (IO a) where
  pack' fmt acc = do
    print fmt
    mapM_ print acc
    return undefined

instance (PackArg a, PackType r) => PackType (a -> r) where
    pack' fmt acc = \x -> pack' fmt $ acc ++ [toPackArg x]

pack :: (PackType t) => String -> t
pack fmt = pack' fmt []

main :: IO ()
main = do
  pack "asd" "qwe" "asd"(1 :: Int) -- Ok
  pack "asd" "qwe" "asd" 1         -- Sad

В указанном случае у меня есть ошибка

test1.hs:33:3-6: No instance for (PackArg a0) arising from a use of ‘pack’ …
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
  instance PackArg String
    -- Defined at /home/knesterov/test1.hs:13:10
  instance PackArg Int -- Defined at /home/knesterov/test1.hs:10:10
In a stmt of a 'do' block: pack "asd" "qwe" "asd" 1
In the expression: do { pack "asd" "qwe" "asd" 1 }
In an equation for ‘main’: main = do { pack "asd" "qwe" "asd" 1 }
test1.hs:33:26: No instance for (Num a0) arising from the literal ‘1’ …
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
  instance Num Double -- Defined in ‘GHC.Float’
  instance Num Float -- Defined in ‘GHC.Float’
  instance Integral a => Num (GHC.Real.Ratio a)
    -- Defined in ‘GHC.Real’
  ...plus 7 others
In the fourth argument of ‘pack’, namely ‘1’
In a stmt of a 'do' block: pack "asd" "qwe" "asd" 1
In the expression: do { pack "asd" "qwe" "asd" 1 }
Compilation failed.

РЕДАКТИРОВАТЬ

Спасибо user5402, который указал на разницу между ghci и ghc. Ghci включает расширение ExtendedDefaultRules по умолчанию

Так что с тремя дополнительными строками мой пример работает без ошибок.

{-# LANGUAGE ExtendedDefaultRules #-}
instance PackArg Integer where
  toPackArg = PackInt . fromIntegral

1 ответ

Решение

Проблема здесь:

The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
  instance Num Double -- Defined in ‘GHC.Float’
  instance Num Float -- Defined in ‘GHC.Float’
  ...

Напомним, что буквальное 1 можно интерпретировать как значение любого Num тип, поэтому GHC не знает, какой из них выбрать - например, Int, Double, Rational, так далее.

Стандарт Text.Printf Модуль имеет ту же проблему:

import Text.Printf

main = putStrLn $ printf "%d" 3

выдает он ту же ошибку.

Обратите внимание, что если вы не получите ошибку, если вы введете этот код в ghci, потому что существуют правила по умолчанию, которые делают выражение 1 мономорфный вместо полиморфный.

Другие вопросы по тегам