题
您可以转换
-- 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'变量)?
解决方案
下面是我得到的。需要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")
请注意箭头函数的(>>>)强>相当于为翻转(。)强>
我个人认为这是很清楚了,但是这个怎么样:
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
在Kleisli组合物操作者>=>
(从Control.Monad)是用于创建pointfree单子功能是有用的。
不隶属于 StackOverflow