#haskell #types #io #pretty-print
#haskell #типы #io #pretty-печать
Вопрос:
Я не понимаю эту ошибку типа:
Couldn't match expected type `[t0]' with actual type `IO ()'
In the return type of a call of `printv'
In a stmt of a 'do' expression: px <- printv x
In the expression:
do { px <- printv x;
sep <- print ", ";
rest <- prints xs;
return (px : sep : rest) }
От:
data Value = IntValue Int
| TruthValue Bool
deriving (Eq, Show)
printv :: Value -> IO()
printv (IntValue i) = print i
printv (TruthValue b) = print ("boolean" show b)
prints :: [Value] -> [IO()]
prints [] = []
prints (x:xs) = do px <- printv x
sep <- print ", "
rest <- prints xs
return (px:sep:rest)
Мне кажется, что каждый элемент ( px
) преобразуется в IO()
действие, а затем добавляется к списку одинаковых объектов, создавая таким образом [IO()]
список.
Чего мне здесь не хватает? Преобразование его в список строк, путем удаления печати, работает нормально.
Ответ №1:
Вы упускаете return
в []
случае prints
:
prints [] = return []
Однако ваши отпечатки очень странные. Он возвращает a [()]
, потому что print
выводит строки на консоль, а не возвращает их.
Вы имеете в виду возвращать строки из вашей printv
функции?
Поскольку вы пытаетесь красиво напечатать синтаксическое дерево, вот примерно правильный способ сделать это:
- Используйте комбинаторы pretty-printing
- Используйте симпатичный класс типов
Вот так:
import Text.PrettyPrint
import Data.List
data Value
= VInt Int
| VBool Bool
deriving (Eq, Show)
class Pretty a where
pretty :: a -> Doc
instance Pretty Value where
pretty (VInt i) = int i
pretty (VBool b) = text "Boolean" < > text (show b)
draw :: [Value] -> String
draw = intercalate ", " . map (render.pretty)
main = putStrLn $ draw [VInt 7, VBool True, VInt 42]
Запуск его:
*A> main
7, Boolean True, 42
Ответ №2:
Присмотритесь повнимательнее к типу вашей функции:
prints :: [Value] -> [IO()]
Но если мы теперь посмотрим на prints [] = []
, это не может совпадать, потому что тип этого
prints :: [t] -> [a]
Следовательно, вы пропустили использование prints [] = return []
, чтобы заставить его работать.
Комментарии:
1. Спасибо имеет смысл — но затем просто возвращает:
code
Не удалось сопоставить ожидаемый типIO ()' with actual type
[a0]’ В первом аргументеreturn', namely
[]’ В выражении: return [] В уравнении для `prints’: prints [] = return []2. Вы правы.
return (px:sep:rest)
имеет типIO [()]
(удалите подпись типа и шаблонprint [] = []
, затем загрузите его в ghci, чтобы попробовать. Посмотрите тип с помощью:i prints
). Следовательно, типprints
должен бытьprints :: [Value] -> IO [()]
. При этом использованиеprint [] = return []
работает.
Ответ №3:
Если вы не оцениваете действие ввода-вывода, вам не нужен do
блок. Просто обрабатывайте IO ()
как обычный тип.
prints (x:xs) = printv x : print ", " : prints xs
Ответ №4:
Вы не хотите prints
возвращать массив действий ввода-вывода. Вы хотите, чтобы оно возвращало одно действие ввода-вывода, представляющее каждое из связанных вместе действий ввода-вывода. Что-то вроде:
prints xs = mapM_ (x -> printv x >> putStr ", ") xs
За исключением того, что я не думаю, что новые строки окажутся там, где вы хотите.
Посмотрите на документацию для mapM
и sequence
для получения дополнительной информации. В частности, реализация sequence, вероятно, похожа на то, что вы пытаетесь сделать.
Однако я бы действительно рекомендовал, чтобы вместо выполнения всей работы в функции ввода-вывода вы написали чистую функцию для отображения текстового формата, который вы хотите, а затем просто распечатали это. В частности, кажется, что экземпляр Show
for Value
был бы уместен.
instance Show Value where
show (IntValue i) = show i
show (TruthValue b) = "boolean " show b
Таким образом, вы можете просто вызывать print value
вместо printv value
, и если вы действительно хотите, вы могли бы определить prints
следующим образом.
import Data.List
prints :: (Show a) => [a] -> IO ()
prints = putStrLn . intercalate ", " . map show`.
Комментарии:
1. Спасибо. Я переделаю это — я просто экспериментировал с использованием списка действий, как в некоторых ранних примерах в SOE. Пытаюсь освоить ввод-вывод и создавать блоки. После того, как я со всем этим разобрался, мне больше нравится ваше использование Show! Тем не менее, я хотел бы выяснить, почему мой исходный код терпит неудачу, даже если он не такой оптимальный.