将自定义数据类型转换为字符串

问题描述:

如果我有三种数据类型,分别为ExprOpFu将自定义数据类型转换为字符串

data Expr = Num Double 
      | X 
      | Operator Op Expr Expr 
      | Function Fu Expr 
      deriving (Eq) 

data Op = Add | Mul 
     deriving (Eq) 

data Fu = Sin | Cos 
     deriving (Eq) 

我应该做的是后来创建一个基于数据类型的表达式。例如

let anExpr = Add (Num 3.0) (Num 4.0) 

而且打印出相应的表达式,在这种情况下,它应该只是“3.0 + 4.0”。

我面临的问题是创建另一种类型或数据类型来识别它是否应该打印出来的加法或乘法符号。我想要做的就是这样的伪代码

printOut (Num n) = show n 
printOut X = "x" 
printOut (Op a b) = printOut a ++ 'printOutRightOp' ++ printOut b 
printOut (Fu a) = 'printOutRightFu' ++ printOut a 

我该如何做到这一点? 。

+0

但是'Op'和'Fu'在'Expr'是建设者的** **的名字。 –

+0

对不起,修正了这个问题 – Salviati

+0

@Salviati你刚开始有一个拼写错误,应该是“如果我有三种数据类型** Expr **,Op和Fu”...... – jkeuhlen

不能写入类型的引用作为构造名。在您的代码:

data Expr = Num Double 
      | X 
      | Op Expr Expr 
      | Fu Expr 
      deriving (Eq)

OpFu是构造的名。 Haskell认为这是一个同名的类型,这只是一个巧合。您必须添加操作符/函数的类型作为第一个参数。所以:

data Expr = Num Double 
      | X 
      | Op Op Expr Expr 
      | Fu Fu Expr 
      deriving (Eq)

现在第二OpFu指定类型的第一个参数。

现在,所以你必须更换:

let anExpr = Add (Num 3.0) (Num 4.0) 

有:

let anExpr = Op Add (Num 3.0) (Num 4.0) 

此基础上,我们可以定义一些帮手功能:

showOp :: Op -> String 
showOp Add = "+" 
showOp Mul = "*" 

showFu :: Fu -> String 
showFu Sin = "sin" 
showFu Cos = "cos" 

现在我们当我们定义我们的时可以使用这些帮助函数(我不会叫它printOut,因为功能确实不是而是打印的东西,它只会产生一个字符串,你可以对该字符串做任何你想做的事情)。

showExpr :: Expr -> String 
showExpr (Num n) = show n 
showExpr X = "x" 
showExpr (Op o a b) = '(' : showExpr a ++ ')' : showOp o ++ '(' : showExpr b ++ ")" 
showExpr (Fu f a) = showFu f ++ '(' : showExpr a ++ ")" 

例如:

*Main> showExpr (Op Add (Num 3.0) (Num 4.0)) 
"(3.0)+(4.0)" 
*Main> showExpr (Op Add (Num 3.0) (Fu Sin (Num 4.0))) 
"(3.0)+(sin(4.0))" 

当你的模式匹配,你需要匹配你传递的构造在您的例子,一个Expr可以有一个Operator构造包含相关信息打印:

printOut (Num n) = show n 
printOut X = "x" 
printOut (Operator op a b) = printOut a ++ printOp op ++ printOut b 
printOut (Function fu a) = printFun fu ++ printOut a 

现在你只定义附加图案为您的操作符和函数匹配:

printOp Add = "+" 
printOp Mul = "x" 

printFun Sin = "Sin" 
printFun Cos = "Cos" 

除了什么@WillemVanOnsem写的,你居然不打印任何东西到屏幕上与这些“打印”功能。相反,你正在将它们从你的数据类型转换成一个字符串。有一种常见的类型类别叫做Show。你也可以只创建节目的情况下,为你的类型,并使用该功能,而不是显示它们:

instance Show Fu where 
    show Sin = "Sin" 
    show Cos = "Cos" 

然后用show代替:

printOut (Function fu a) = show fu ++ printOut a 

当你拥有的show一个简单的实例,您也可以使用与您使用衍生的相同语法为您自动导出它:Eq

data Fu = Sin | Cos 
     deriving (Show, Eq) 

为了应对创造Expr一个实例,再使用各种构造这样做:

let anExpr = Operator Add (Num 3.0) (Num 4.0) 
+0

Ty太多了,真的感觉数据类型是现在更清晰了。在被理解之前,这真的是一个痛苦的屁股。 – Salviati

+2

显示实例通常应该打印有效的Haskell代码,可以通过合理的Read实例将其读回为相同的值。当你想以不同的格式打印数据时,就像这里一样,最好为它定义一个单独的函数,而不是重新调整Show。 – amalloy

+0

@amalloy好点。你仍然可以创建一个自定义的'read'实例来满足'read'。 show == id',但在这种情况下,你可能不希望操作符。也许'Fu'型在这里是一个更好的例子。 – jkeuhlen