我有一个带洞的Traversable
- 想象一下这个二叉树:
/ \
/ \ Nothing
Just 1 / \
Nothing Just 3
我还有一个值列表,用 - [2, 4]
填补漏洞 - 导致:
/ \
/ \ Just 4
Just 1 / \
Just 2 Just 3
我认为可以使用lens
索引遍历来遍历Nothing
并将其替换为列表中相应索引处的值。
但是必须可以在不使用指数的情况下直接做更多的事情吗?
奖励积分 - 此主题的一些变体:
Maybe
表示。[2, 4, 6]
,[2, 4, ..]
等。答案 0 :(得分:5)
如果没有足够的元素,这是一个返回Left
的版本。
您可以使用Traversable
monad中的mapM
State
来填补漏洞:
import qualified Data.Traversable as T
import Control.Monad.State.Strict
import Control.Error
import qualified Data.Tree as Tree
import Data.Tree (Tree(..))
visit :: Maybe a -> ExceptT String (State [a]) a
visit (Just x) = return x
visit Nothing = do xs <- lift get
case xs of
(a:as) -> do lift (put as); return a
[] -> throwE "out of elements"
fill :: T.Traversable t => t (Maybe a) -> [a] -> Either String (t a)
fill t vals = evalState (runExceptT (T.mapM visit t) ) vals
tree = Node Nothing [ Node (Just "2") [], Node Nothing [] ]
ex1 = print $ fill tree ["a", "b", "c", "d" ] -- Right ...
ex2 = print $ fill tree ["a" ] -- Left "out of elements"
如果您想确保使用所有元素,请将fill
更改为:
fill :: T.Traversable t => t (Maybe a) -> [a] -> Either String (t a)
fill t vals = evalState (runExceptT doit) vals
where doit = do t' <- T.mapM visit t
xs <- lift get
case xs of
[] -> return t'
_ -> throwE "not all elements were used"
答案 1 :(得分:5)
利用mapAccumL
的简单(但部分)解决方案:
import qualified Data.Traversable as T
fill :: forall a t. T.Traversable t => t (Maybe a) -> [a] -> t a
fill t fillers = snd $ T.mapAccumL go fillers t
where
go :: [a] -> Maybe a -> ([a], a)
go fs (Just x) = (fs, x)
go (f:fs) Nothing = (fs, f)
go [] Nothing = error "not enough fillers!"
完全替代方案:
fill2 :: forall a t. T.Traversable t =>
t (Maybe a) -> [a] -> Maybe (t a)
fill2 t fillers = sequenceA . snd $ T.mapAccumL go fillers t
where
go :: [a] -> Maybe a -> ([a], Maybe a)
go (f:fs) Nothing = (fs, Just f)
go fs x = (fs, x)
答案 2 :(得分:3)
这是一个紧凑的:
var onClick = function() {
var cars = ["Saab", "Volvo", "BMW"];
var rows = "";
rows += "<tr><td> " + cars[0] + " </td></tr>";
$(rows).appendTo("#list tbody");
};
$('#button').click(onClick);