将函数列表的组合应用于列表的每个数字
Apply the composition of a list of functions to each number of a list
给定一个函数列表和一个数字列表,我希望将第一个函数应用于数字列表,然后将结果用于第二个函数,依此类推。
wantedFunc [(*2), (+2), (/2)] [1,2,3,4]
| | |
| | |
V | |
[2,4,6,8]---| |
| |
V |
[4,6,8,10]---|
V
[2,3,4,5] -- End result
是否有内置函数?
类似
import Control.Arrow ((>>>))
wantedFunc :: Foldable t => t (a -> a) -> [a] -> [a]
wantedFunc fs = map f
where
f = compose fs
compose = foldr (>>>) id
成功了:
λ> wantedFunc [(*2), (+2), (/2)] [1, 2, 3, 4]
[2.0,3.0,4.0,5.0]
正确的折叠解决方案是:
fun :: (Functor f, Foldable t) => t (a -> a) -> f a -> f a
fun = foldr (\f -> (. fmap f)) id
那么,
\> fun [(*2), (+2)] [1,2,3,4]
[4,6,8,10]
\> fun [(*2), (+2), (`div` 2)] [1,2,3,4]
[2,3,4,5]
这是一个 fmap fmap
方法,使用 Monoid 来组合函数。
newtype Endo a = Endo { unwrap :: a -> a }
instance Monoid (Endo a) where
mempty = Endo id
mappend (Endo f) (Endo g) = Endo (g . f)
wantedFunc = unwrap . mconcat . fmap (Endo . fmap)
λ wantedFunc [(*2), (+2), (/2)] [1,2,3,4]
[2.0,3.0,4.0,5.0]
单线解决即可
> map (foldr (.) id $ reverse [(*2),(+2),(/2)]) [1..4]
[2.0,3.0,4.0,5.0]
只需组合所有功能并应用地图。
wantedFunc :: [a->a] -> [a] -> [a]
wantedFunc fs = map (foldl1 (.) fs)
直接应用您的定义我们得到
wantedFunc :: [(a -> a)] -> [a] -> [a]
wantedFunc fs xs = foldl (\ys f -> map f ys) xs fs
但我们可以改造
foldl (\ys f -> map f ys) xs fs
foldl (\ys f -> flip map ys f) xs fs -- flip map
foldl (flip map) xs fs -- remove lambda
flip (foldl (flip map)) fs xs -- flip foldl
flip (foldl (flip map)) -- remove lambda
flip $ foldl $ flip map -- or using ($)
最后
wantedFunc :: [(a -> a)] -> [a] -> [a]
wantedFunc = flip $ foldl $ flip map
另一方面,我们可以更改函数签名翻转参数和函数列表顺序,我们可以将该函数写成
wantedFunc' :: [a] -> [(a -> a)] -> [a]
wantedFunc' = foldr map
例如
main = do
print $ wantedFunc [(*2), (+2), (/2)] [1,2,3,4]
print $ wantedFunc' [1,2,3,4] [(/2), (+2), (*2)]
有输出
[2.0,3.0,4.0,5.0]
[2.0,3.0,4.0,5.0]
给定一个函数列表和一个数字列表,我希望将第一个函数应用于数字列表,然后将结果用于第二个函数,依此类推。
wantedFunc [(*2), (+2), (/2)] [1,2,3,4]
| | |
| | |
V | |
[2,4,6,8]---| |
| |
V |
[4,6,8,10]---|
V
[2,3,4,5] -- End result
是否有内置函数?
类似
import Control.Arrow ((>>>))
wantedFunc :: Foldable t => t (a -> a) -> [a] -> [a]
wantedFunc fs = map f
where
f = compose fs
compose = foldr (>>>) id
成功了:
λ> wantedFunc [(*2), (+2), (/2)] [1, 2, 3, 4]
[2.0,3.0,4.0,5.0]
正确的折叠解决方案是:
fun :: (Functor f, Foldable t) => t (a -> a) -> f a -> f a
fun = foldr (\f -> (. fmap f)) id
那么,
\> fun [(*2), (+2)] [1,2,3,4]
[4,6,8,10]
\> fun [(*2), (+2), (`div` 2)] [1,2,3,4]
[2,3,4,5]
这是一个 fmap fmap
方法,使用 Monoid 来组合函数。
newtype Endo a = Endo { unwrap :: a -> a }
instance Monoid (Endo a) where
mempty = Endo id
mappend (Endo f) (Endo g) = Endo (g . f)
wantedFunc = unwrap . mconcat . fmap (Endo . fmap)
λ wantedFunc [(*2), (+2), (/2)] [1,2,3,4]
[2.0,3.0,4.0,5.0]
单线解决即可
> map (foldr (.) id $ reverse [(*2),(+2),(/2)]) [1..4]
[2.0,3.0,4.0,5.0]
只需组合所有功能并应用地图。
wantedFunc :: [a->a] -> [a] -> [a]
wantedFunc fs = map (foldl1 (.) fs)
直接应用您的定义我们得到
wantedFunc :: [(a -> a)] -> [a] -> [a]
wantedFunc fs xs = foldl (\ys f -> map f ys) xs fs
但我们可以改造
foldl (\ys f -> map f ys) xs fs
foldl (\ys f -> flip map ys f) xs fs -- flip map
foldl (flip map) xs fs -- remove lambda
flip (foldl (flip map)) fs xs -- flip foldl
flip (foldl (flip map)) -- remove lambda
flip $ foldl $ flip map -- or using ($)
最后
wantedFunc :: [(a -> a)] -> [a] -> [a]
wantedFunc = flip $ foldl $ flip map
另一方面,我们可以更改函数签名翻转参数和函数列表顺序,我们可以将该函数写成
wantedFunc' :: [a] -> [(a -> a)] -> [a]
wantedFunc' = foldr map
例如
main = do
print $ wantedFunc [(*2), (+2), (/2)] [1,2,3,4]
print $ wantedFunc' [1,2,3,4] [(/2), (+2), (*2)]
有输出
[2.0,3.0,4.0,5.0]
[2.0,3.0,4.0,5.0]