Tricky! Es un mecanismo realmente bueno para comparar los valores con (==) en el último momento y solo si es necesario. ¿Por qué no lo comentaste al menos con información tipo?
data Tree a = E | T (Tree a) a (Tree a)
insert :: (Ord a) => a -> Tree a -> Tree a
insert x t = const t `either` id $ insert' x t Nothing
where
-- insert' (insert_this) (into_this_empty_tree) (except_if_it_equals_this) (because_then_the_tree_is_Left_unchanged)
insert' :: (Ord a) => a -> Tree a -> Maybe a -> Either (Tree a) (Tree a)
insert' x E Nothing = Right (T E x E)
insert' x E (Just v) | x==v = Left E
| otherwise = Right (T E x E)
-- insert' (insert_this) (into_this_nonempty_tree) ((anyway)) (recursive:if_it_branches_to_the_left_insert_it_there)
-- insert' (insert_this) (into_this_nonempty_tree) ((anyway)) (recursive:if_it_equals_or_branches_to_the_right_insert_it_there_except_if_the_right_branch_is_empty)
insert' x [email protected](T l v r) _ | x<v = (\l' -> T l' v r) `fmap` insert' x l Nothing
| otherwise = (\r' -> T l v r') `fmap` insert' x r (Just v)
¿Por qué utilizar cualquiera, si tiras el caso Izquierda distancia y luego utilice una copia? Sería más eficiente si no mantienes esa copia para reemplazar un árbol igual y, en cambio, no construyes un árbol igual. De alguna manera como esto ...
insert' :: (Ord a) => a -> Tree a -> Maybe a -> Maybe (Tree a)
Y entonces ... si quieres ser realmente eficaz, no construir ese (Tal vez un) parámetro sólo para compararlo después.
--insert'1 :: (Ord a) => a -> Tree a -> Nothin -> Maybe (Tree a)
--insert'2 :: (Ord a) => a -> Tree a -> Just a -> Maybe (Tree a)
insert'1 :: (Ord a) => a -> Tree a -> Maybe (Tree a)
insert'2 :: (Ord a) => a -> Tree a -> a -> Maybe (Tree a)
La solución se vería así:
insert :: (Ord a) => a -> Tree a -> Tree a
insert x t = fromMaybe t $ insert'1 x t
where
insert'1 :: (Ord a) => a -> Tree a -> Maybe (Tree a)
insert'2 :: (Ord a) => a -> Tree a -> a -> Maybe (Tree a)
insert'1 x E = Just (T E x E)
insert'1 x (T l v r) | x<v = do l' <- insert'1 x l
Just (T l' v r)
| otherwise = do r' <- insert'2 x r
Just (T l v r')
insert'2 x E v = guard (x/=v) >> Just (T E x E)
insert'2 x t _ = insert'1 x t
(EDITAR :)
En Control.Monad.Error es esta instancia definida:
Error e => MonadError e (Either e)
Eso significa, que (Either String) es probablemente lo que está buscando.
insert :: (Ord a,MonadError String m) => a -> Tree a -> m (Tree a)
insert x t = maybe (throwError "Error: element already in tree") return $ insert'1 x t
where ...
también echar un vistazo a la [Control de errores] capítulo (http://book.realworldhaskell.org/read/error-handling.html) en el libro _Real Mundial Haskell_. –
Nitpick: si no usas 'Left' para el caso de error, no puedes convertir' Either' en un functor, mónada, etc., que es lo más importante; no son solo dos significados de * derecha *. –
@Antal S-Z: Personalmente, pensé que era solo porque [el lado izquierdo es malo] (http://en.wiktionary.org/wiki/sinister#Etymology). –