2009-12-13 3 views
2

Я определил тип данных для двоичных чисел следующегореверса двоичных чисел в Haskell

data Bin = Nil | O Bin | I Bin 
      deriving (Show, Eq) 

я хочу, чтобы определить функцию reverse :: Bin -> Bin так, что, когда я внести свой вклад как

reverse (I (O (I (I Nil)))) я должен получить outut I (I (O (I Nil))), что означает обратный как вход, любое тело, пожалуйста, дайте мне подсказку, как я могу это сделать?

+0

Просто для внутренней информации, даже если это чужое определение, они комбинируя идеи списка и двоичное число, когда он гораздо проще удержать их отдельно, а затем объединить их вместе. Это, по сути, точка haskell: состав частей. Просто поймите, если вам нужно было ввести определение, которое лучше (решение Айдана Калли). – codebliss

+3

Я, вероятно, вообще не создавал бы никаких новых типов: 'Bool' уже является подходящим типом бит, а' [] 'уже является подходящим типом списка. Возможно, создание псевдонима типа Bin = [Bool]. – ephemient

ответ

8

Почему вы так делаете? Почему не что-то вроде этого:

data Bit = I | O 
newtype Bin = List Bit 

Тогда вы могли бы просто использовать обратную операцию прелюдии непосредственно ...

Редактировать Простая подстановка из функции Prelude в:

reverse x = rev x [] 
    where 
    rev [] a = a 
    rev (x:xs) a = rev xs (x:a) 

дает :

reverse x = rev x Nil 
    where 
    rev Nil a = a 
    rev (I xs) a = rev xs (I a) 
    rev (O xs) a = rev xs (O a) 

Дело в том, ваш тип очень похож на тип списка:

data List a = a : (List a) | [] 

поэтому логика для списка подпрограмм относится непосредственно к вашему типу.

+0

нет, дело в том, что мне не разрешено изменять тип данных, я должен сделать это в данных типа данных – dinsim

+0

Большое спасибо Aidan, – dinsim

+1

'newtype Bin = List Bit' не имеет смысла. Возможно, вы имели в виду «тип Bin = List Bit» или «newtype Bin = List [Bit]» или «newtype Bin = Bin (бит списка)» или что-то подобное. – Rotsor

2

List модуля GHC определяет функцию reverse в списках, как это:

reverse l = rev l [] 
    where 
    rev []  a = a 
    rev (x:xs) a = rev xs (x:a) 

Вспомогательная функция rev использует свой второй элемент в качестве аккумулятора, который хранит перевернутую часть до текущей позиции. На каждом шаге первый элемент оставшегося списка ввода добавляется в головку аккумулятора, который передается в вызов рекурсивной функции.

Этот же принцип может применяться к вашему двоичному типу номера, чтобы изменить порядок цифр.

+0

Я не уверен, что могу применить понимание списка здесь, потому что у меня есть вход как '(I (O (I (I Nil))))' – dinsim

+0

Да, вы, вероятно, не можете использовать понимание списка. – sth

1

Кажется странным, что вы определяете тип списка и тип битов. Я думаю, что я бы повторно использовал список базовых библиотек типа [] и просто установил элементы в качестве вашего битового типа, как показано выше в Aidan.

6
data Bin = Nil | O Bin | I Bin deriving (Show, Eq) 
reverse :: Bin -> Bin 
reverse x = rev Nil x 
    where 
     rev a Nil = a 
     rev a (O b) = rev (O a) b 
     rev a (I b) = rev (I a) b 
4
binToList Nil = [] 
binToList (O a) = False : binToList a 
binToList (I a) = True : binToList a 

listToBin [] = Nil 
listToBin (False : xs) = O (listToBin xs) 
listToBin (True : xs) = I (listToBin xs) 

reverseBin = listToBin . reverse . binToList 
+0

listToBin можно сделать в fold: listToBin = foldr (\ bd -> if b then (I d) else (O d)) [] –

+0

Или даже 'foldr (\ b -> if b then I else O) [ ] '. – ephemient

+0

Или даже 'foldr ((!!) [O, I]. FromEnum) []', если бы вы чувствовали себя особенно точечно сегодня. – ephemient

0

это возможное решение:

reverseBin :: Bin -> Bin 
reverseBin b = revBin b Nil 
      where revBin Nil acc = acc 
        revBin (I b) acc = revBin b (I acc) 
        revBin (O b) acc = revBin b (O acc) 
Смежные вопросы