Ошибка при компиляции печати Любое значение
Я пытаюсь скомпилировать простой фрагмент кода.
main = (putStrLn . show) (Right 3.423)
Скомпилируйте результаты в следующей ошибке:
No instance for (Show a0) arising from a use of `show'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Show Double -- Defined in `GHC.Float'
instance Show Float -- Defined in `GHC.Float'
instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
...plus 42 others
In the second argument of `(.)', namely `show'
In the expression: putStrLn . show
In the expression: (putStrLn . show) (Right 3.423)
Когда я выполняю тот же фрагмент из ghci, все работает как ожидалось.
Prelude> let main = (putStrLn . show) (Right 3.423)
Prelude> main
Right 3.423
Итак, вопрос в том, что происходит?
1 ответ
Проблема в том, что GHC не может определить, какой полный тип Right 3.423
есть, он может только определить, что он имеет тип Either a Double
и случай Show
за Either
похоже instance (Show a, Show b) => Show (Either a b)
, Без этого дополнительного ограничения на Either a Double
GHC не знает, как его распечатать.
Причина, по которой он работает в интерактивном режиме, заключается в страшном ограничении мономорфизма, которое делает GHCi более агрессивным по умолчанию, который он выбирает. Это можно отключить с помощью :set -XNoMonomorphismRestriction
и это станет по умолчанию в будущих версиях GHC, так как это создает много проблем для начинающих.
Решение этой проблемы - поставить подпись типа на Right 3.423
в вашем исходном коде, как
main = (putStrLn . show) (Right 3.423 :: Either () Double)
Здесь я только что использовал ()
за a
, поскольку нас это все равно не волнует, и это "самый простой" тип, который можно показать. Вы могли бы поставить String
или же Int
или же Double
или что вы там хотите, пока это реализует Show
,
Совет, putStrLn . show
это именно определение print
так что вы можете просто сделать
main = print (Right 3.423 :: Either () Double)
Как указывает @ØrjanJohansen, это не ограничение мономорфизма, а ExtendedDefaultRules
расширение, которое использует GHCi, которое по сути делает именно то, что я сделал выше, и пихает ()
в переменные типа, чтобы заставить вещи работать в интерактивном сеансе.