【问题标题】:How do I print the name and value of a custom data type in Haskell如何在 Haskell 中打印自定义数据类型的名称和值
【发布时间】:2014-03-25 03:28:56
【问题描述】:

假设我定义了一个数据类型如下:

data OP = Plus | Minus | Num Int     deriving (Show, Eq)

然后我获取strings 的列表,并获取它们各自的OP 值列表,如下所示:

getOp :: [String] -> [OP]
getOp [] = []
getOp (x:rest)
        | x == "+" = Plus:(getOp rest)
        | isInfixOf "Num" x == True = Num (read (drop 4 x) :: Int):(getOp rest)
        | otherwise = "-" = Minus:(getOp rest)

然后我想显示[OP] 列表,用新行分隔。我已经很容易地用字符串列表完成了它,但不确定如何处理数据类型列表。

我有以下结构作为起点:

showOp :: [OP] -> String
showOp [] = []
showOp (o:os) = (putStr o):'\n':(showOp os)

我知道最后一行是错误的。我试图在第一部分返回[Char],然后是Char,然后是递归调用。我为最后一行(见下文)尝试了一些其他变体,但没有成功。

showOp o = show o  (works but not what I need. It shows the whole list, not each element on a new line

showOp o = putStrLn (show o)   (epic fail)

showOp o 
    | o == "+" = "Plus\n":(showOp os)
    | more of  the same. Trying to return a [Char] instead of a Char, plus other issues.

另外,我不确定Num Int 类型的输出需要如何不同,因为我需要显示类型名称和值。

这方面的示例 i/o 如下所示:

在:

getOp ["7","+","4","-","10"]

出来:

Num 7
Plus
Num 4
Minus
Num 10

【问题讨论】:

  • 永远不要说 x==True。直接说 x。

标签: function haskell types show


【解决方案1】:

您需要查看您正在使用的函数和对象的类型Hoogle 是获取函数签名的绝佳资源。

对于初学者来说,putStr 的签名是

putStr :: String -> IO ()

但您的代码有putStr o,其中o 不是字符串,结果不应是IO ()。你真的希望showOp 打印 Op,还是只是为它创建一个多行字符串?

如果是前者,则需要showOp的签名来体现:

showOp :: [Op] -> IO ()

然后你可以使用一些do-notation 来完成这个功能。

我会为你给定的类型签名写一个解决方案。因为showOp 应该返回一个StringputStr 返回一个IO (),所以我们不会在任何地方使用putStr。请注意,String 只是 [Char] 的类型同义词,这就是我们可以将 Strings 视为列表的原因。

showOp :: [Op] -> String
showOp [] = [] -- the empty list is a String
showOp (o:os) = showo ++ ('\n' : showos)
   where showo = (show o) -- this is a String, i.e. [Char]
         showos = showOp os -- this is also a String

showoshowos 都是 Strings:showshowOp 都返回 Strings。 我们可以使用 cons 操作 : 将单个字符添加到字符列表中。我们可以使用追加运算符 ++ 追加两个字符串列表。

现在你可能想要另一个功能

printOp :: [Op] -> IO ()
printOp xs = putStr $ showOp xs

【讨论】:

  • 这很有帮助,谢谢。我唯一的问题是如何在不更改“[OP] -> String”签名的情况下将 printOp 合并到 showOp 中,以便 showOp 的结果在输出的新行中包含每个元素?
  • 您不能*使用签名 [Op]->StringprintOp 合并到 showOp 中。正如我上面解释的,有两个单独的步骤:将列表转换为String,然后打印String。每次打印时,您都需要*在签名中添加IO ()。 *:技术上不正确,但出于您的目的,请认为它是正确的。
【解决方案2】:

怎么样:

showOp = putStrLn . unlines . map show

请注意,您的数据构造函数OP 已经是Show 的一个实例。因此,您实际上可以将map show 放入包含OP 类型成员的数组中。之后,事情就变得非常简单了。

简单的几条笔记...

你可能想要:

getOp :: [String] -> [OP]
getOp [] = []
getOp (x:rest)
        | x == "+"                  = Plus:(getOp rest)
        | x == "-"                  = Minus:(getOp rest)
        | isInfixOf "Num" x == True = Num (read (drop 4 x) :: Int):(getOp rest)
        | otherwise                 = (getOp rest)

而不是你所拥有的。你的程序有语法错误...

接下来,您想提供的输入可能是

["Num 7","+","Num 4","-","Num 10"]

?。我想那是一个错字。

【讨论】:

  • 注意,如果你想保留你的类型签名,只需去掉putStrLn函数...
猜你喜欢
  • 1970-01-01
  • 2018-09-17
  • 1970-01-01
  • 2011-12-20
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
  • 2012-03-12
相关资源
最近更新 更多