Tricky!
It is a really nice mechanism to compare the values with (==) at the last moment and only iff needed. Byt why didn't you comment it at least with type information?
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 t@(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)
Why did you use Either, if you throw the Left case away and then use a copy? It would be more efficient, if you would not hold that copy to replace an equal tree, and instead do not build an equal tree at all. Somehow like this...
insert' :: (Ord a) => a -> Tree a -> Maybe a -> Maybe (Tree a)
And then... if you want to be really efficient, don't build that (Maybe a) parameter just to compare it afterwards.
--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)
The solution would look like this:
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
(EDIT:)
In Control.Monad.Error is this instance defined:
Error e => MonadError e (Either e)
That means, that (Either String) is probably what you are looking for.
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 ...