在Haskell中删除字符串的双引号

3

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

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:当你显示String值时,请不要加上双引号?


问题似乎在于(只有t)中的“t”可以是一个字符串,一个包含字符串的值集合或另一种类型的值。如果它不是一个字符串,它就可以正常打印;如果它是一个字符串,它就会显示该字符串。我不确定如何解决这个问题。 - emi
你能解释一下,你是如何为变量t定义show方法的吗? - fuz
那其实不重要;他正在对字符串运行show函数,而且String的show函数已经被定义为双引号加上字符串加双引号。他想要避免的就是这些双引号。 - jrockway
也许你可以引入一个新的类型类,它基于 show 并在除了 String 以外的所有情况下都使用 show,并在这种情况下仅返回原始字符串。请记住,show 实际上就像其他语言中的 toString 一样,旨在打印调试信息,最好不要将其用于其他任何目的或定义自定义实例。 - JonnyRaa
4个回答

8

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

1
你可以像这样定义自己的类型类:
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" 子句。但是您确实需要所有实例,这有点麻烦。

或者,您可以使用 重叠实例。我认为(尽管我没有尝试过),这将允许您使用单行替换默认的 "gShow" 实例列表:

instance (Show a) => GShow a

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


-1

看起来有点丑,但你可以对 show t 应用一个 filter

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

难道不应该是filter (!='"') (show t)吗?顺便说一句,这也会从输入中删除转义的",这似乎不是预期的行为。 - fuz
@FUZxxl:这个问题只是要求删除双引号,没有提到转义的双引号。 - Matt Ellen
1
@FUZxxl:记得 (/=) /= (!=) - muhmuhten

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接