Бессмысленная форма против стиля
Вы можете конвертировать
-- 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)
Какие соглашения об именах лучше использовать (см. Переменные ps, ps', es и es)?
3 ответа
Вот что я получил. потребности Control.Arrow (&&&)
а также Control.Applicative (<$>)
,
tupleUnfold :: Int -> ExpQ
tupleUnfold n = do
y <- newName "y"
(ps,es) <- unzip . map (varP &&& (`appE` varE y) . varE)
<$> replicateM n (newName "x")
lamE [tupP ps, varP y] (tupE es)
Невозможно сделать что-то еще, не сделав его совершенно непонятным.
РЕДАКТИРОВАТЬ Хотя это не точка бесплатно, вот самое ясное, что я мог сделать это. потребности 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
Немного более непонятно (попробуйте читать справа налево):
tupleUnfold n = do
y <- newName "y"
uncurry lamE . ((:[varP y]) . tupP *** tupE) . unzip .
map (varP &&& (`appE` varE y) . varE) <$> replicateM n (newName "x")
РЕДАКТИРОВАТЬ:
смесь стрелок и состав функции для обработки
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")
обратите внимание, что функция стрелки (>>>) эквивалентна функции flip (.)
Лично я думаю, что это уже понятно, но как насчет этого:
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) полезен для создания бессмысленных монадических функций.