2011-02-04 4 views
1

Как можно просто написать flipv один раз, применяя его к каждому элементу списка [se, sq, nw, ne], давая результат (не как список конечно) для Q конструктора?Применить функцию к списку и передать его результат конструктору?

data (Eq a, Show a) => QT a = C a | Q (QT a) (QT a) (QT a) (QT a) 
    deriving (Eq, Show) 

flipv :: (Eq a, Show a) => QT a -> QT a 
flipv (C a) = C a 
flipv (Q nw ne se sw) = Q (flipv se) (flipv sw) (flipv nw) (flipv ne) 

EDIT: обратите внимание, это на самом деле не так, потому что указатели должны быть: NW NE SW SE. не

+1

+1, потому что я повеселился, пытаясь ответить на него =) –

+3

Кстати, вы должны отбросить '(Eq a, Показать a) =>' из типа 'data'. См. Http://learnyouahaskell.com/making-our-own-types-and-typeclasses#algebraic-data-types для объяснения (после «Тем не менее, это очень сильное соглашение в Haskell, чтобы никогда не добавлять ограничения типов в объявлениях данных. .. ") – Landei

ответ

2

Существует не особенно простой и компактный метод, но вы можете попробовать это:

flipv :: (Eq a, Show a) => QT a -> QT a 
flipv (C a) = C a 
flipv (Q nw ne se sw) = Q se' sw' nw' ne' 
    where [nw', ne', se', sw'] = map flipv [nw, ne, se, sw] 
+0

кажется довольно нечитаемым, я искал элегантный способ ... – gremo

+0

@Gremo, выглядит довольно хорошо для меня. Возможно, ваши глаза нуждаются в обучении.Или это может выглядеть уродливо для вас, потому что вы ожидаете чего-то более простого, но то, что вы хотите, не выражается в системе типов. – luqui

-1

его применение к каждому элементу списка [с, кв, Nw, п], что дает результат (не как список) к конструктору Q?

принимает список и выбрасывает QT.

data (Eq a, Show a) => QT a = C a | Q (QT a) (QT a) (QT a) (QT a) 
    deriving (Eq, Show) 

flipv :: (Eq a, Show a) => [a] -> QT a 
flipv [nw, ne, se, sw] = Q (C se) (C sw) (C nw) (C ne) 

main = do 
    print (Q (C 1) (C 2) (C 3) (C 4)) 
    (print . flipv) [1, 2, 3, 4] 
+0

Не то, что я имею в виду, это упрощает 'Q (flipv se) (flipv sw) (flipv nw) (flipv ne)'. – gremo

1

Вместе first glance, я was going к suggest toList и fromList. Это больше кода, но в конце он дает элегантную композицию.

toList :: QT a -> [QT a] 
toList (Q w x y z) = [w,x,y,z] 

fromList :: [QT a] -> QT a 
fromList [w,x,y,z] = Q w x y z 

listOpOnQT :: ([QT a] -> [QT a]) -> QT a -> QT a 
listOpOnQT _ (C a) = C a 
listOpOnQT f q  = fromList . map (listOpOnQT f) . f . toList $ q 

flipv :: QT a -> QT a 
flipv = listOpOnQT reverse 

затягивая испытания в GHCI

ghci> let q = Q (Q (C 1) (C 2) (C 3) (C 4)) (C 22) (C 33) (C 44) 
ghci> q 
Q (Q (C 1) (C 2) (C 3) (C 4)) (C 22) (C 33) (C 44) 
ghci> flipv q 
Q (C 44) (C 33) (C 22) (Q (C 4) (C 3) (C 2) (C 1)) 

Вы можете легко сделать 'сортировки' работа на структуре интервала QT, а также, в настоящее время.

import Data.List (sort) 
instance (Ord a) => Ord (QT a) where 
    compare (C x) (C y) = x `compare` y 
    compare (C x) _ = LT 
    compare _ (C x) = GT 
    compare _ _ = EQ 

sortv :: (Ord a) => QT a -> QT a 
sortv = listOpOnQT sort 

Испытано в рамках предыдущей сессии GHCI ...

ghci> sortv it 
Q (C 22) (C 33) (C 44) (Q (C 1) (C 2) (C 3) (C 4)) 
ghci> sortv q 
Q (C 22) (C 33) (C 44) (Q (C 1) (C 2) (C 3) (C 4)) 

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


Итак, как это работает?

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

+0

Это на самом деле хороший ответ, но не ответ. Я искал что-то кратким и строгим, я имею в виду, не используя никакой дополнительной функции, кроме стандартной прелюдии. – gremo

+1

@ Гремо да, я так понял. Я начал, пытаясь понять, может ли что-то вроде fmap делать трюк, но если вы не сделаете QT экземпляром пары классов, то вы не можете сделать это из коробки (afaik). –

+0

Я возражаю против этого ad-hoc экземпляра «Ord». Я бы предпочел написать отдельную функцию сравнения, например. 'compareLeaves' и использовать' sortBy'. Этот экземпляр «Ord» не учитывает расширение типа данных (и, ИМО, вряд ли является естественным). В противном случае хороший ответ. – luqui

1

В принципе нет простого способа сделать это, не перечисляя все четыре аргумента, так как в противном случае, как вы можете убедиться, что список имеет правильное число (4) элементов?

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