2013-09-04 2 views
3

я определяю тип Octave:Как написать заказное шоу функции в Haskell

data Octave = 1 | 2 | 3 
    deriving (Show, Read, Ord, Enum) 

С «1» не является действительной для идентификаторов конструктора данных, я должен сделать это как так:

data Octave = O1 | O2 | O3 
    deriving (Show, Eq, Read, Ord, Enum) 

Теперь, если я show Octave O1, он показывает «O1», что не совсем то, что я хочу. Я хочу, чтобы результат был «1». Я знаю, что мы можем настроить наше шоу поведение, как это:

instance Show Blabla where                      
    show (Blabla ints chars list num) =                    
    "integers = " ++ show ints ++ "\n" 

Но проблема в том, что я использую тип перечисления, который означает, что он не имеет значения, кроме его имени идентификатора «О1». Как я могу получить доступ к этому в Haskell?

Другой вопрос: как я могу его прочитать?

read "O1" :: Octave работает, но я хочу read "1" :: Octave

instance Read Octave where 
    read "1" = O1 
    read "2" = O2 
    read "3" = O3 

Это не работает: "read не (видимый) метод класса Read".

ответ

2

Вы всегда можете использовать существующие экземпляры для Int, например, так:

data Octave = O1 | O2 | O3 deriving (Enum,Bounded) 

instance Show Octave where 
    show = show . (+1) . fromEnum 

instance Read Octave where 
    readsPrec pr = map (\ (int,str) -> ((toEnum (int-1)),str) . readsPrec pr 

Это правильно делает O1..O3, как 1..3 и читает их обратно. Единственный подводный камень при попытке прочитать другое целое число, как 4:

*** Exception: toEnum{Octave}: tag (3) is outside of enumerations'range (0,2) 

Это может быть исправлен путем записи больше коды и проверки допустимых значений в readsPred.

4

Кажется, что все, что вам нужно, это, верно?

instance Show Octave where 
    show O1 = "1" 
    show O2 = "2" 
    show O3 = "3" 

Определение show с тремя пунктами, и пусть Сличитель шаблон цифра.

+0

Любые лучшие способы? – yehe

+0

Лучше, чем «функции отлично, тривиально легко писать»? – amalloy

+0

Что делать, если Octave имеет 8 значений? – yehe

1

Похоже, вы хотите получить доступ к имени идентификатора. вы можете использовать что-то вроде template haskell, но это ужасная идея.

На самом деле, самая плохая идея, вероятно, полагаться на show. Класс Show традиционно используется для «сериализации» данных, а класс Read де-сериализует их. Если вы хотите распечатать вывод, вам лучше написать свою собственную функцию Octave -> String. Для этого вы можете полагаться на результат show (и обрезать результат). Тем не менее, наиболее эффективным решением может быть его непосредственное кодирование, как предлагается amalloy.

+0

Thx, как насчет его прочтения. Меня это очень беспокоит. Мне предлагается реализовать функцию, которая должна следовать объявлению функции. И он передает мне струны !!! – yehe

+1

Тот факт, что GHCi использует 'show' для отображения результатов, является достаточно хорошей причиной для того, чтобы сделать экземпляр ADTs' Show', даже если нет возможности сериализовать/десериализовать их, IMHO. –

+0

Также довольно легко добавить «prettyPrint». перед вашей линией ghc (или после этого «prettyPrint it»). – Nicolas

6

Воспользовавшись Enum примеру Октава и использование экземпляров Show и Read для Int мы можем осуществить показ и чтение так:

data Octave = O1 | O2 | O3 deriving (Eq, Ord, Enum) 

instance Show Octave where 
    show o = show (fromEnum o + 1) 

instance Read Octave where 
    readsPrec prec = map (\(n,s) -> (toEnum (n - 1), s)) . readsPrec prec 

Т.е.fromEnum и toEnum конвертировать между октавами и Интс, так что O1 < ->0 и O2 < ->1, поэтому мы должны настроить один в чтения и записи.

5

Вот другой подход:

data Octave_ = O1 | O2 | O3 deriving (Show, Eq, Read, Ord, Enum) 
newtype Octave = O { unO :: Octave_ } deriving (Eq, Ord, Enum) 

instance Show Octave where 
    show = tail . show . unO 

В зависимости от того, что вы делаете это может быть хорошим или плохим.

Смежные вопросы