我正在尝试编写自己的函数,该函数接受任意数量的标记,然后在任何标记上拆分任意字符串。
经过一番思考后,我相信我需要递归迭代一个标记列表,然后将每个拆分列表传递给一个带有拆分功能的地图,然后展平。
目前,我的算法看起来像这样:
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
被投射到[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"]]
这里的类型签名究竟发生了什么?这是映射的正确方法吗?我错过了什么?
答案 0 :(得分: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