Удаление двойных кавычек в Haskell - PullRequest
3 голосов
/ 18 сентября 2010

Эта функция генерирует простые файлы .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" ++ ")\" ]"

, где wrap, wrapSp и mapSp - функции форматирования, как deltaTuples.

Проблема в том, что formatGraph сохраняет двойные кавычки вокруг строк, что приводит к ошибкам в Graphviz. Например, когда я печатаю unlines $ prepGraph в файл, я получаю такие вещи:

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

вместо

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

(Тем не менее, "Null", кажется, работает нормально, и выводит отлично). Теперь, конечно, строка «N. SF» не является реальной формой, которую я использую для хранения перегибов, но эта форма содержит строку или два. Итак, как я могу сказать Haskell: когда вы show значения String, не ставьте его в двойные кавычки?

Ответы [ 4 ]

6 голосов
/ 19 сентября 2010

Посмотрите, как Мартин Эрвиг справился с той же проблемой в 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 голосов
/ 18 сентября 2010

Использовать пакет dotgen - в нем предусмотрены специальные меры безопасности для предотвращения проникновения запрещенных символов в значения атрибутов.

1 голос
/ 18 сентября 2010

Вы можете определить свой собственный тип 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" для каждого экземпляра.Но вам нужны все экземпляры, что немного затруднит.

В качестве альтернативы вы можете использовать перекрывающиеся экземпляры .Я думаю (хотя я не пробовал), что это позволит вам заменить список экземпляров, использующих gShow по умолчанию, одной строкой:

instance (Show a) => GShow a

Идея состоит в том, что с перекрывающимися экземплярами компиляторвыберет наиболее конкретный доступный экземпляр.Так что для строк он выберет экземпляр строки над более общим, а для всего остального общий является единственным, который соответствует.

0 голосов
/ 18 сентября 2010

Кажется немного уродливым, но вы можете применить filter к show t

filter (/='"') (show t)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...