获取数据并将其转换为字符串

时间:2014-10-02 20:52:17

标签: haskell

给出以下代码:

data Exprs = Const Double
        | Var String      --in math we often use char
        | Sqrt Exprs      --we can take sqrt of anything
        | IntPow Exprs Int--the easy case of exponents
        | Exp Exprs       --e^expr
        | Ln Exprs        --logarithms
        | Mult Exprs Exprs--multiplication
        | Add Exprs Exprs
        | Neg Exprs
deriving (Show, Eq, Ord)

x = Var "x"
y = Var "y"
z = Var "z"


-- to multiply x and y we type in "Mult x y"

example = Add (Const 7) ( Mult (Const 4) (Add (Sqrt x) (Exp y)))

我如何制作一个从示例中显示7 + 4 *(sqrt(x))+ e ^ y的函数?

3 个答案:

答案 0 :(得分:2)

您要在此处实现的是showsPrec类型类中的Show函数。此函数使用一个额外的参数来指示操作的优先级,允许您更容易地实现理智的括号,并且它也更有效,因为它使用相当于差异列表来构建字符串(更有效的连接)。函数show默认为\x -> showsPrec 0 x "",因此当您致电show时,它将正常运行。你的案例的一个不完整的例子是

data Exprs
    = Const Double
    | Var String      --in math we often use char
    | Sqrt Exprs      --we can take sqrt of anything
    | IntPow Exprs Int--the easy case of exponents
    | Exp Exprs       --e^expr
    | Ln Exprs        --logarithms
    | Mult Exprs Exprs--multiplication
    | Add Exprs Exprs
    | Neg Exprs
    deriving (Eq, Ord)

instance Show Exprs where
    showsPrec n (Const x)  = showParen (n > 10) $ showsPrec 11 x
    showsPrec n (Var var)  = showParen (n > 10) $ showString var
    showsPrec n (Add l r)  = showParen (n >  6) $ showsPrec 7 l . showString "+" . showsPrec 7 r
    showsPrec n (Mult l r) = showParen (n >  7) $ showsPrec 8 l . showString "*" . showsPrec 8 r
    showsPrec n (Sqrt e)   = showParen (n > 10) $ showString "sqrt(" . shows e . showString ")"

我会留给你实现其他构造函数(并测试它以确保没有错误,我不保证这是100%正确),但你应该有一个很好的开始。您可能希望尝试使用:i (*):i (+):i (**)来确定我使用的优先级来自何处。

答案 1 :(得分:2)

正如我在对@ ThreeFx的回答中发表评论时,我认为使用Show类型类进行漂亮打印或其他常规字符串修改是不好的做法。 Show的文档指出,对于派生实例,“show的结果是一个语法正确的Haskell表达式”由构造函数,常量等组成。这本身并不是一个规则,但它是一个非常有用的不变量。例如,当您在ghci中计算表达式时,您希望得到一个结果,然后您可以在代码中复制粘贴和重用。使用Show执行您想要的操作会打破期望。

相反,我认为您应该公开一个函数 - 而不是show - 您可以正确记录等,并且不会违反Show实例上的隐式契约。 @Bakuriu在评论中提出了同样的建议。

该功能的实现几乎与@ThreeFx和@bheklilr提出的解决方案相同......只是没有instance部分。这是我对@ bheklilr版本的再现:

data Exprs
    = Const Double
    | Var String      --in math we often use char
    | Sqrt Exprs      --we can take sqrt of anything
    | IntPow Exprs Int--the easy case of exponents
    | Exp Exprs       --e^expr
    | Ln Exprs        --logarithms
    | Mult Exprs Exprs--multiplication
    | Add Exprs Exprs
    | Neg Exprs
    deriving (Eq, Ord, Show, Read)

prettyPrint :: Exprs -> String
prettyPrint e = go 0 e ""
  where
    go n (Const x)  = showParen (n > 10) $ showsPrec 11 x
    go n (Var var)  = showParen (n > 10) $ showString var
    go n (Add l r)  = showParen (n >  6) $ go 7 l . showString "+" . go 7 r
    go n (Mult l r) = showParen (n >  7) $ go 8 l . showString "*" . go 8 r
    go n (Sqrt e)   = showParen (n > 10) $ showString "sqrt(" . go n e . showString ")"

请注意,我所做的只是机械地将showsPrec重写为go并将其包装在便利函数中。

现在ReadShow工作花花公子,我们可以获得漂亮的印刷效果:

*SO26169469> Add (Const 7) ( Mult (Const 4) (Add (Sqrt (Var "x")) (Const 3)))
Add (Const 7.0) (Mult (Const 4.0) (Add (Sqrt (Var "x")) (Const 3.0)))
*SO26169469> show it
"Add (Const 7.0) (Mult (Const 4.0) (Add (Sqrt (Var \"x\")) (Const 3.0)))"
*SO26169469> read it :: Exprs
Add (Const 7.0) (Mult (Const 4.0) (Add (Sqrt (Var "x")) (Const 3.0)))
*SO26169469> prettyPrint it
"7.0+4.0*(sqrt(x)+3.0)"

P.S。我并不自称是任何权威;我相信很多人会像其他贡献者所建议的那样支持使用Show

答案 2 :(得分:0)

小心:提前做坏事!

正如克里斯蒂安在他的评论中指出的那样,show应该产生一个语法上有效的Haskell结构,这就是为什么重写show不被认为是好的做法。你应该看看bheklilr的回答或Bakuriu对这个问题的评论。


然而,一种可能的方法是为每个构造函数手动实现Show实例:

instance Show Exprs where
  show (Const d) = show d
  show (Var   v) = v
  show (Sqrt ex) = "(sqrt(" ++ show ex ++ "))"
  ..
  show (Add e1 e2) = show e1 ++ " + " ++ show e2
  ..

示例输出:

*Main> Sqrt (Var "x")
(sqrt(x))
*Main> Add (Sqrt (Const 4)) (Var "x")
(sqrt(4.0)) + x
相关问题