I was writing a function (named
listenString) in haskell to see if a string contains one of the strings in a list of strings, and to then return a value (of the type
m ()) that corresponded with the string it found. The type of that function is
(Eq a, Monad m) => [a] -> [([a], m ())] -> m ().
The reason why I used a list to store the strings and their corresponding values (
[([a], m ())]) instead of a Map was because I wanted to make sure that the function evaluated strings in the order that they were in the list, e.g.
listenString "hello there" [("lo",print True),("hello",print False)] would printed
True. If I used a map, the order might have been lost, and the function might have printed
Here's the code. I'm specifically wondering if there are any bugs, and if I'm using
ListT correctly (of if I should be using something other than
ListT), but any other feedback would be helpful and appreciated.
import Data.Either import Control.Monad.Trans.List searchListMapMaybe f (Search a b c) = Search a (mapMaybe f b) c data Search a b = Search a [a] b type Searching a b = ListT (Either b) (Search a b) listenString  _ = return () listenString a l = let list = filter (\(x,_) -> if (x == ) then False else True) l noEmptyList  = error "listenForString: You need to have at least one item in the list" noEmptyList x = x in listenStringSub a $ ListT $ Data.Either.Right $ fmap (\(x,y) -> Search x  y) $ noEmptyList list where listenStringSub :: (Eq a) => [a] -> Searching [a] (m b) -> m b listenStringSub _ (ListT (Data.Either.Left a)) = a listenStringSub (c:cs) x = listenStringSub cs $ (listenStringMap c x) >>= searchFinal where listenStringMap char x = fmap ((searchReduce char) . (searchPop char)) x searchPop :: (Eq a) => a -> Search [a] b -> Search [a] b searchPop char (Search a@(x:_) l b) | char == x = Search a (a:l) b | otherwise = Search a l b searchReduce :: (Eq a) => a -> Search [a] b -> Search [a] b searchReduce char search = searchListMapMaybe (function char) search where function _  = Just  function c l@(x:xs) | c == x = Just xs | otherwise = Nothing searchFinal :: (Eq a) => Search [a] b -> Searching [a] b searchFinal s@(Search a b c) |  `elem` b = ListT (Data.Either.Left c) | otherwise = return s
listenString should decide what values to return in the following order:
- Which list comes first:
listenString "hello there" [("lo",print True),("he",print False)]would output
- If two or more strings end in the exact same place, e.g.
listenString "hello there" [("lo",print True),("hello",print False)], I want the tuple closest to the beginning of the list to be displayed (the above expression would output