文字列の部分スプリット

http://karetta.jp/article/blog/oneline/012507より。ちっともHaskellらしくないけども。

*Main> partial_split "long time ago" []
["long","time","ago"]
*Main> partial_split "    long       time     ago" []
["long","time","ago"]
*Main> partial_split "long time ago" ["time"]
["long","time ago"]
*Main> partial_split "long time ago" ["ago"]
["long","time","ago"]
*Main> partial_split "long time ago" ["long","time"]
["long time ago"]
*Main> partial_split "long long time ago" ["long"]
["long long time","ago"]
*Main> partial_split "      long        long long time ago" ["long"]
["long        long long time","ago"]
partial_split line sep
    | null sep = map fst $ separate l
    | otherwise = let ss = separate line in iter [] "" ss sep
    where l = dropWhile (== ' ') line

iter :: [String] -> String -> [(String,String)] -> [String] -> [String]
iter ret str [] sep = filter (/= "") $ ret ++ [str]
iter ret str [(f,s)] sep = iter (ret ++ [str,f]) "" [] sep
iter ret str ((f,s):y@(f',s'):xs) sep
    | elem f sep && elem f' sep = iter ret (str ++ f ++ s) (y:xs) sep
    | elem f sep = iter (ret ++ [str ++ f ++ s ++ f']) "" xs sep
    | otherwise  = iter (ret ++ [str,f]) "" (y:xs) sep

separate :: String -> [(String,String)]
separate "" = []
separate l  = let (f,l') = break (== ' ') l
                  (s,l'') = break (/= ' ') l'
              in (f,s):separate l''