Красивая печать синтаксического дерева в Haskell - PullRequest
0 голосов
/ 20 апреля 2011

Я не понимаю этот тип ошибки:

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()].

Чего мне здесь не хватает?Преобразование его в список строк путем удаления отпечатков работает нормально.

Ответы [ 4 ]

3 голосов
/ 20 апреля 2011

Вам не хватает return на [] случае prints:

prints  []    = return []

Однако ваши отпечатки очень странные. Он возвращает [()], потому что print выводит строки в консоль, а не возвращает их.

Вы хотите вернуть строки из вашей printv функции?


Поскольку вы пытаетесь довольно красиво распечатать синтаксическое дерево, вот примерно правильный способ сделать это:

Вот так:

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 голосов
/ 20 апреля 2011

Присмотритесь к типу вашей функции:

prints :: [Value] -> [IO()]

Но если мы теперь посмотрим на prints [] = [], это не может соответствовать, потому что тип этого

prints :: [t] -> [a]

Поэтому вы пропустили использование prints [] = return [], чтобы оно заработало.

1 голос
/ 21 апреля 2011

Вы не хотите, чтобы prints возвращал массив действий ввода-вывода. Вы хотите, чтобы он возвращал одно действие ввода-вывода, которое представляет каждое из связанных действий ввода-вывода. Что-то вроде:

prints xs = mapM_ (\x -> printv x >> putStr ", ") xs

За исключением того, что я не думаю, что новые строки будут заканчиваться там, где вы хотите.

Посмотрите документацию для mapM и sequence для получения дополнительной информации. В частности, реализация последовательности, вероятно, похожа на то, что вы пытаетесь сделать.

Однако я действительно рекомендую вместо того, чтобы выполнять всю работу в функции ввода-вывода, написать чистую функцию для визуализации желаемого текстового формата, а затем просто распечатать его. В частности, кажется, что экземпляр Show для 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 голос
/ 20 апреля 2011

Если вы не оцениваете действие ввода-вывода, вам не нужен блок do. Просто относитесь к IO () как к нормальному типу.

prints (x:xs) = printv x : print ", " : prints xs
...