参数改变类型的Haskell映射?

时间:2014-03-26 03:23:17

标签: haskell map functional-programming

我正在尝试编写自己的函数,该函数接受任意数量的标记,然后在任何标记上拆分任意字符串。

经过一番思考后,我相信我需要递归迭代一个标记列表,然后将每个拆分列表传递给一个带有拆分功能的地图,然后展平。

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

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"]]

这里的类型签名究竟发生了什么?这是映射的正确方法吗?我错过了什么?

1 个答案:

答案 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