2014-03-26 74 views
0

我正在尝试编写我自己的函数,它接受任意数量的标记,然后将任意一个字符串分开。Haskell映射与参数更改类型?

经过一番思考之后,我相信我需要递归遍历一个标记列表,然后将每个分割列表传递给具有分割函数的贴图,然后将其展平。

目前,我的算法看起来像这样:

module MyAwesomeModule where 

import qualified Data.Text as T 

outputSplit :: String -> [String] -> IO() 
outputSplit s tokens = print $ splitRecursive tokens s 

splitRecursive :: [String] -> String -> [String] 
splitRecursive tokens s = splitOneOf tokens s 

splitOneOf :: [String] -> String -> [String] 
splitOneOf [] s = [] 
splitOneOf (t:tokens) s = map (splitOneOf tokens)(map (T.unpack) (T.splitOn (T.pack t) (T.pack s))) ++ (splitOneOf tokens s) 

与错误了:

Couldn't match type `[Char]' with `Char' 
Expected type: String -> String 
    Actual type: String -> [String] 
In the return type of a call of `splitOneOf' 
In the first argument of `map', namely `(splitOneOf tokens)' 
In the first argument of `(++)', namely 
    `map 
    (splitOneOf tokens) 
    (map (T.unpack) (T.splitOn (T.pack t) (T.pack s)))' 

所以,据我了解,这是什么意思的是,String S IN初始分割被转换为[Char]

Prelude > let a = (map (T.unpack) (T.splitOn (T.pack "a") (T.pack "abcdefabc"))) 
      ["","bcdef","bc"] 
      :t a 
      a::[String] 
      let b = head a 
      :t b 
      b::String 

此外,如果splitOneOf被定义为:

splitOneOf :: [String] -> String -> [String] 
    splitOneOf [] s = [] 
    splitOneOf (t:tokens) s = (map (T.unpack) (T.splitOn (T.pack t) (T.pack s))) ++ (splitOneOf tokens s) 

然后

Prelude > let a = splitOneOf ["a", "b"] "abcdefghij" 
      ["", "bcdefghij"] 
      map (splitOneOf ["b"]) a 
      [[""], [[""],["cdefghij"]] 

到底是一个什么在这里的类型签名?这是映射的正确方法吗?我错过了什么?

+1

为什么地图有三个参数?你的意思是把'splitOneOf tokens'放入禁忌中吗? – Emil

+0

感谢您指出,我已经相应地修改了这个问题 –

+0

没有必要使用Data.Text。有Data.List.Split。 –

回答

1
import Control.Monad ((>=>)) 
import Data.List.Split (splitOn) 

--|Using list monad, for repeated concatMaps 
splitOnMany :: [String] --^delimiters 
      -> String --^input 
      -> [String] --^output 
splitOnMany [] = return 
splitOnMany (d:ds) = splitOn d >=> splitOnMany ds 

该列表单子通常被认为是某种穷人的非确定性或逻辑单子。但是,无论何时您需要对列表进行递归展平,都可以使用它。在这里,我们分割第一个分隔符,然后分割所有第二个分隔符,等等,然后将所有东西弄平。我很确定明确的递归也不是真的有必要。以下是更通用的,甚至可能更好地优化:

import Control.Monad ((>=>)) 
import Data.List.Split (splitOn) 

splitOnMany :: Eq a => [[a]] -> [a] -> [[a]] 
splitOnMany = foldr (>=>) return . map splitOn 
+0

我认为列表单子monad只会遮盖这里的问题,它实际上只是'splitonMany令牌行= foldr(concatMap。splitOn)[行]令牌'。 –

+0

对于你的,为什么不foldl'?对我而言,额外的严格规定并没有帮助。我认为我的内线更好,因为它没有任何问题。你说得对,Kleisli鱼可能不是太澄清;也许我最近刚刚想到monad。 –