gpt4 book ai didi

Haskell - 与数据类型匹配的模式

转载 作者:行者123 更新时间:2023-12-04 15:17:28 25 4
gpt4 key购买 nike

我有这样的数据类型和函数:

data Expr = Num Int | Add Expr Expr | Mult Expr Expr | Neg Expr | If Expr Expr Expr deriving (Show, Read)

prettyPrint :: Expr -> IO ()
prettyPrint expr = prettyPrint' expr 0


prettyPrint' :: Expr -> Int -> IO ()
prettyPrint' (Num x) i = putStrLn $ concat (replicate i " ") ++ "Num " ++ show x

prettyPrint' (Add x y) i = do
putStrLn $ concat (replicate i " ") ++ "Add"
prettyPrint' x (i+1)
prettyPrint' y (i+1)

prettyPrint' (Mult x y) i = do
putStrLn $ concat (replicate i " ") ++ "Mult"
prettyPrint' x (i+1)
prettyPrint' y (i+1)

prettyPrint' (Neg x) i = do
putStrLn $ concat (replicate i " ") ++ "Neg"
prettyPrint' x (i+1)

prettyPrint' (If x y z) i = do
putStrLn $ concat (replicate i " ") ++ "If"
prettyPrint' x (i+1)
prettyPrint' y (i+1)
prettyPrint' z (i+1)

在我使用模式匹配的函数中。问题是他们对代码有很多重用。例如, Mult 的情况和 Add基本上是相同的代码。 Num 也是如此和 Neg .有没有办法根据表达式有多少变量来写这个?喜欢 NumNeg ,因为它们只有一个变量。 Mult 的一个案例和 Add ,因为它们有两个变量。最后一个案例 If ,因为该表达式具有三个变量。

笔记:

我得到了这个答案,我认为这是一个比我开始时更好的解决方案:
prettyPrint :: Expr -> IO () 
prettyPrint expr = putStrLn (prettyPrint' 1 expr)

prettyPrint' :: Int -> Expr -> String
prettyPrint' i (Num x) = "Num " ++ show x
prettyPrint' i expr =
let indent x = concat (replicate i " ") ++ x
(op, args) = case expr of
Add x y -> ("Add", [x,y])
Mult x y -> ("Mult", [x,y])
Neg x -> ("Neg", [x])
If x y z -> ("If", [x,y,z])
in intercalate "\n" (op : map (indent . prettyPrint' (i + 1)) args)

最佳答案

首先,我会尽可能长时间地远离 IO monad。有prettyPrint'返回要打印的字符串。

prettyPrint :: Expr -> IO ()
prettyPrint = putStrLn . prettyPrint'

现在, prettyPrint' 的唯一工作是创建一个(可能是多行的)要打印的字符串。对于数字,这很简单:只需使用 show实例。
prettyPrint' :: Expr -> String
prettyPrint' e@(Num _) = show e
-- or, ignoring the Show instance for Expr altogether
-- prettyPrint' (Num x) = "Num " ++ show x

其余的,有一个模式:
  • 识别构造函数
  • 确定它的论点
  • 用换行符加入构造函数名称及其 pretty-print 的参数。每个参数将相对于其运算符缩进一级;递归将处理多个级别的缩进。

  • 看起来像
    prettyPrint' expr = let indent x = "    " ++ x
    (op, args) = case expr of
    Add x y -> ("Add", [x,y])
    Mult x y -> ("Mult", [x,y])
    Neg x -> ("Neg", [x])
    If x y z -> ("If", [x,y,z])
    in intercalate "\n" (op : map (indent . prettyPrint') args)

    例如,考虑 prettyPrint'将使用表达式 Add (Num 3) (Num 5) .首先,它设置 op"Add"args[Num 3, Num 5] .接下来,它映射 indent . prettyPrint'在参数列表上,得到 [" Num 3", " Num 5"] .将运算符放在列表的前面会产生 ["Add", " Num 3", " Num 3"] ,然后用 intercalate 加入他们生产 "Add\n Num 3\n Num 5" .

    唯一剩下的样板在 case表达。我认为可以消除它,但它需要一定程度的我不熟悉的通用编程。我敢肯定,其他人可能会用我的答案来解决这个问题。

    关于Haskell - 与数据类型匹配的模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53284410/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com