2011-12-16 6 views
3

Я пытаюсь сделать особый тип экземпляром Show.Определение Показать произвольный рекурсивный тип в Haskell

Вот этот тип, это всего лишь базовый тип Set.

data Set a = Insert a (Set a) | EmptySet 

Я хотел бы что-то вроде

Insert 1 (Insert 2 (Insert 3 EmptySet)) 

для отображения как

{1, 2, 3} 

Как это сделать? Я попытался сделать это с помощью конкатенации строк, но похоже, что интерполяция строк считается плохой формой (Haskell, похоже, не поддерживает это?) Также, как мне получить фигурные скобки вокруг списка? До сих пор все, что я был в состоянии приготовить был этот, который в основном ничего не делает ...

instance (Show a) => Show (Set a) where 
    show EmptySet = "" 
    show (Insert a as) = show a ++ show as 

Кроме того, я пытался использовать Hoogle и Hayoo найти реализацию списка, так что я мог видеть, как это было реализовано на Списки. Я не мог найти его. У кого-нибудь есть указатели на это? Я попытался найти «show :: [a] -> String», «Data.Lists», «Lists» и т. Д.

+3

Кстати, это, вероятно, плохая идея. Результат 'show' должен быть действительным кодом Haskell, который дает значение, равное значению, переданному' show'. Я предлагаю определить функцию 'fromList' и сделать' show' на множестве {1, 2, 3}, например, 'fromList [1, 2, 3]'; это подход, используемый стандартными библиотеками Data.Map и Data.Set. Кроме того, вы можете определить свою собственную функцию, которая делает это для вызова вместо 'show' для просмотра наборов в этой нотации. – ehird

ответ

5

Вот решение с прямой рекурсии:

instance Show a => Show (Set a) where 
    show = ('{' :) . go 
    where 
     go EmptySet   = "}" 
     go (Insert x EmptySet) = show x ++ "}" 
     go (Insert x xs)  = show x ++ ", " ++ go xs 

Если вам не нравится, неэффективное использование (++), вы можете, конечно, использовать difference lists:

instance Show a => Show (Set a) where 
    show = ('{' :) . ($ []) . go 
    where 
     go EmptySet   = ('}' :) 
     go (Insert x EmptySet) = shows x . ('}' :) 
     go (Insert x xs)  = shows x . (", " ++) . go xs 

Это должно сделать это; так что давайте проверим:

> show (Insert 2 (Insert 3 (Insert 5 EmptySet))) 
"{2, 3, 5}" 
+1

Если вам не нравится неэффективное использование '(++)', вы должны реализовать 'showPrec' вместо' show'. –

+0

@SjoerdVisscher: Я согласен, конечно, но я хотел продемонстрировать дельта с первой реализацией. –

4

Тип данных может быть рекурсивным, но это не является причиной для рекурсивной функции ,

import Data.List (intercalate) 

instance Show a => Show (Set a) where 
    show x = "{" ++ intercalate ", " (toList x) ++ "}" 

Предполагается, что у вас есть функция toList :: Set a -> [a]. Рекурсия скрыта там.

Реализация списка осуществляется с помощью showList функции от Show typeclass (так что String с, также известные [Char] s, могут отображаться по-разному).

+0

Я вроде как нуб, но разве это не перерыв, потому что список должен содержать элементы одного типа? Если я передам список чисел в эту функцию, не будет ли это ошибка типа? –

+1

Набор, который вы определили, также должен содержать элементы того же типа. В 'Insert a (Установить a)', это все 'a'. Так что проблем не должно быть. – redxaxder

5

Этот тип по-прежнему гомоморфен списку. Где этот экземпляр Show определен; Вы все еще можете использовать его:

toList (Insert a b) = a:toList b 
toList EmptySet = [] 

instance Show a => Show (Set a) where 
    show = show . toList 
Смежные вопросы