【问题标题】:Removing String double-quotes in Haskell在 Haskell 中删除字符串双引号
【发布时间】:2010-09-18 06:25:32
【问题描述】:

此函数生成简单的 .dot 文件,用于使用 Graphviz 可视化自动机转换函数。它的主要目的是调试大量自动生成的转换(例如,拉丁动词的变形)。

prepGraph :: ( ... ) => NFA c b a -> [String]
prepGraph nfa = "digraph finite_state_machine {"
              : wrapSp "rankdir = LR"
              : wrapSp ("node [shape = circle]" ++ (mapSp (states nfa \\ terminal nfa)))
              : wrapSp ("node [shape = doublecircle]" ++ (mapSp $ terminal nfa))
              : formatGraph nfa ++ ["}"]

formatGraph :: ( ... ) => NFA c b a -> [String]
formatGraph = map formatDelta . deltaTuples
 where formatDelta (a, a', bc) = wrapSp (mkArrow a a' ++ " " ++ mkLabel bc)
       mkArrow x y   = show x ++ " -> " ++ show y
       mkLabel (y, z) = case z of
         (Just t) -> "[ label = \"(" ++ show y ++ ", " ++ show t ++ ")\" ]"
         Nothing  -> "[ label = \"(" ++ show y ++ ", " ++ "Null" ++ ")\" ]"

其中wrapwrapSpmapSp 是格式化函数,deltaTuples 也是。

问题是formatGraph 在字符串周围保留双引号,这会导致 Graphviz 出现错误。例如,当我将 unlines $ prepGraph 打印到文件时,我会得到如下信息:

0 -> 1 [ label = "('a', "N. SF")" ];

而不是

0 -> 1 [ label = "('a', N. SF)" ];

(但是,“Null”似乎工作正常,并且输出非常好)。现在,字符串“N. SF”当然不是我用来存储变形的实际形式,但该形式确实包含一两个字符串。那么我如何告诉 Haskell:当你 show 一个字符串值时,不要双引号呢?

【问题讨论】:

  • (问题好像是(Just t)中的't'既可以是字符串,也可以是包含字符串的值的集合,也可以是其他类型的值。如果不是字符串,则打印正常;它是一个字符串,它显示字符串。我不知道如何解决这个问题)。
  • 你能解释一下,你是如何定义 show for t 的吗?
  • 这并不重要;他正在字符串上运行显示,并且字符串显示已定义为 。他想避免的是那些双引号。
  • 不显示字符串,而是将它们连接起来?也许你可以引入一个新的类型类,它建立在 show 之上,并且对除 String 之外的所有内容都使用 show 并在他们的情况下只返回原始字符串。请记住 show 真的很像其他语言中的 toString ,因为它是为打印调试信息而设计的,最佳实践是不要将它用于其他任何事情或定义它的自定义实例

标签: string file-io haskell


【解决方案1】:

看看 Martin Erwig 如何在 Data.Graph.Inductive.Graphviz 中处理同样的问题:

http://hackage.haskell.org/packages/archive/fgl/5.4.2.3/doc/html/src/Data-Graph-Inductive-Graphviz.html

你要找的函数是底部的“sq”:

sq :: String -> String
sq s@[c]                     = s
sq ('"':s)  | last s == '"'  = init s
            | otherwise      = s
sq ('\'':s) | last s == '\'' = init s
            | otherwise      = s
sq s                         = s

(当然,检查上下文并适应您自己的代码)

【讨论】:

    【解决方案2】:

    使用 dotgen 包 - 它有特殊的保护措施来防止禁止的字符潜入属性值。

    【讨论】:

      【解决方案3】:

      您可以像这样定义自己的 typeClass:

      class GShow a where
         gShow :: a -> String
         gShow = show
      
      instance GShow String where
         show = id
      
      instance GShow Integer
      instance GShow Char
      -- And so on for all the types you need.
      

      “gShow”的默认实现是“show”,因此您不需要为每个实例添加“where”子句。但是你确实需要所有的实例,这有点拖累。

      您也可以使用overlapping instances。我认为(尽管我没有尝试过)这将让您使用默认的“gShow”将实例列表替换为一行:

      instance (Show a) => GShow a
      

      这个想法是,对于重叠的实例,编译器将选择最具体的可用实例。因此对于字符串,它将选择字符串实例而不是更通用的实例,而对于其他所有内容,通用的实例是唯一匹配的实例。

      【讨论】:

        【解决方案4】:

        看起来有点难看,但你可以将filter 应用到show t

        filter (/='"') (show t)
        

        【讨论】:

        • 不应该是filter (!='"') (show t)吗?顺便说一句,这也从输入中剥离了转义的",似乎不是这样的。
        • @FUZxxl:这个问题只是要求删除“。它没有提到转义的”。
        • @FUZxxl:记住(/=) /= (!=)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-09
        • 2012-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多