2010-11-21 4 views
6

Вы можете конвертироватьPoint-свободной форме в зависимости от стиля

-- tupleUnfold :: forall a. ((forall b. a -> b)) -> a -> ((b)) 
tupleUnfold :: Int -> ExpQ 
tupleUnfold n = do 
    xs <- forM [1 .. n] (const . newName $ "x") 
    y <- newName "y" 
    let y' = varE y 
     g (ps', es') x = (varP x : ps', appE (varE x) y' : es') 
     (ps, es) = foldl' g ([], []) xs 
    lamE [tupP ps, varP y] (tupE es) 

в pointfree стиле, сохраняя при этом ясность (я знаю, что программы «pointfree», но предпочел бы, чтобы не запутывать код еще больше)?

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

$(tupleUnfold 3) ((+ 1), (+ 2), (+ 3)) 2 
-- (3, 4, 5) 

Какие лучше именования для использования (см пс, пс, эс, Е. С. переменные)?

ответ

5

Вот что я получил. Потребности Control.Arrow (&&&) и Control.Applicative (<$>).

Невозможно слить его гораздо больше, не сделав его совершенно непонятным.

EDIT Пока не свободна, здесь ясный я мог сделать это. Потребности Data.Function (on)

tupleUnfold :: Int -> ExpQ 
tupleUnfold n = do 
    y <- newName "y" 
    xs <- replicateM n (newName "x") 
    let exps = tupE $ zipWith appVars xs (repeat y) 
     pats = tupP $ map varP xs 
    lamE [pats, varP y] exps 
    where 
    appVars = appE `on` varE 
+0

Мне нравится использование «replicateM» - не знаю, как я пропустил этот – ScootyPuff

+0

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

+0

Отчасти причиной складки (вместо карты) было избежать множественных обходов. Я также знаю, что GHC довольно хорош в обходах списка сплайсинга. Это обычно значительная разница? Учитывая, что обе формы относительно легко писать, что должно (как правило,) быть предпочтительным? – ScootyPuff

0

Лично я считаю, что это довольно ясно уже, но как об этом:

tupleUnfold :: Int -> ExpQ 
tupleUnfold = mapM (const . newName $ "x") . enumFromTo 1 >=> \xs -> do 
    y <- newName "y" 
    let y' = varE y 
     g (ps', es') x = (varP x : ps', appE (varE x) y' : es') 
     f ps = lamE [tupP ps, varP y] . tupE 
    uncurry f $ foldl' g ([],[]) xs 

Композиция Оператор Клейсли >=> (от Control.Monad) полезна для создания pointfree монадических функций.

+0

У меня был вариант, который был на pointfree верхнего уровня (используя> =>), но в итоге пришлось сломать его. Хорошо знать, что это относительно ясно, поскольку это - большая часть того, что мне помогает в Haskell, - сколько способов что-то можно переписать. – ScootyPuff

+0

Насколько важны привязки, когда дело доходит до производительности? Это в основном, почему у меня есть y '- я был не уверен, что выражение будет выведено наружу. – ScootyPuff

+0

Да, без вычисления y 'varE y' не будет использоваться общий доступ. Но это вычисление, вероятно, просто делегирует конструктору, поэтому оно не имеет отношения к делу (и не беспокоиться о двух вызовах конструктора по сравнению с одним, что просто позволяет вашему языку вам самому - вы не получите более быстрый код, я просто получаю дрянной код). Простое в foldl 'бесполезно, потому что это обычный (ленивый) кортеж. Используйте строгий кортеж 'data Tuple a b = Tuple! A! B'. Но поскольку это потоковый код, вместо этого используйте 'foldr' - он использует асимптотически меньше памяти. Это в основном составляет 'unzip. map', как в моем ответе. – luqui

1

немного непонятная (попробуйте прочитать справа налево):

tupleUnfold n = do 
    y <- newName "y" 
    uncurry lamE . ((:[varP y]) . tupP *** tupE) . unzip . 
    map (varP &&& (`appE` varE y) . varE) <$> replicateM n (newName "x") 

EDIT:
сочетание стрелок и композиции функций для обработки

tupleUnfold n = do 
    y <- newName "y" 
    uncurry lamE . ((tupP >>> (:[varP y])) *** tupE) . unzip . 
    map (varP &&& (varE >>> (`appE` varE y))) <$> replicateM n (newName "x") 

и используя в основном стрелки (функция обработки чтения слева направо т)

tupleUnfold n = do 
    y <- newName "y" 
    (map (varP &&& (varE >>> (`appE` varE y))) >>> unzip >>> 
    ((tupP >>> (:[varP y])) *** tupE) >>> uncurry lamE) <$> replicateM n (newName "x") 

отметить, что функция стрелка (>>>) эквивалентно флип (.)