你能转换吗
-- 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',但更愿意不再混淆代码)?
无论哪种方式,可以做出哪些改变来改进功能的风格,或者使其意图更清晰?该功能旨在如下使用。
$(tupleUnfold 3) ((+ 1), (+ 2), (+ 3)) 2
-- (3, 4, 5)
要使用哪些更好的命名约定(请参阅ps,ps',es和es'变量)?
答案 0 :(得分:5)
这就是我得到的。需要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
答案 1 :(得分:1)
更难以理解(尝试从右到左阅读):
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")
请注意,箭头功能(&gt;&gt;&gt;)相当于翻转(。)
答案 2 :(得分: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
Kleisli组合运算符>=>
(来自Control.Monad)对于创建无点monadic函数非常有用。