Apply a function to a list and pass its result to a constructor?

286 Views Asked by At

How can just write flipvone time applying it to each element of list [se, sq, nw, ne], giving the result (not as a list of course) to the Q constructor?

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: note this actually wrong because the pointers should be: NW NE SW SE.

4

There are 4 best solutions below

1
Max Bolingbroke On BEST ANSWER

There is no particularly simple or compact method, but you could try this:

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]
1
Yuval Langer On

applying it to each element of list [se, sq, nw, ne], giving the result (not as a list of course) to the Q constructor?

takes a list and throws a 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]
4
Dan Burton On

At first glance, I was going to suggest toList and fromList. It's more code, but it enables elegant composition in the end.

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

Loosely tested in 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))

You can easily make 'sort' work on your QT structure as well, now.

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

Tested as part of the previous ghci session...

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))

Notice sorting the flipped q and just plain q both came out with the same result (therefore the sorting probably works! yay). You might want to pick a better implementation of compare, I just threw that one together to see stuff happen.


So how does it work?

The magic sauce, as you might have guessed, is listOpOnQT. In the non-trivial case, it turns the QT structure into a list, applies the listy function to the list, maps the lifted listy function on all elements of the list, and then pulls the list back into a QT structure. A better name for listOpOnQT might be liftQT, though it only works for a very special kind of function...

0
newacct On

There's basically no simple way to do it without enumerating all four arguments, because otherwise, how can you make sure that the list has the right number (4) of elements?