在Haskell中删除String双引号

时间:2010-09-18 06:25:32

标签: string file-io haskell

此函数生成简单的.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”不是我用来存储变形的实际形式,但是该形式确实包含一个或两个String。那么我怎么能告诉Haskell:当你show一个字符串值时,不要重复引用它?

4 个答案:

答案 0 :(得分:6)

查看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

(查看上下文并适应您自己的代码)

答案 1 :(得分:2)

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

答案 2 :(得分:1)

您可以像这样定义自己的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

我们的想法是,对于重叠的实例,编译器将选择最具体的实例。因此,对于字符串,它将在更一般的字符串上选择字符串实例,而对于其他所有字符串实例,通用字符串实例是唯一匹配的字符串实例。

答案 3 :(得分:-1)

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

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