我正在编写一个函数来生成一组字符串的所有排列 - “foo”应该返回{“foo”,“ofo”,“oof”}。我已经在Clojure中完成了这个,所以我知道这种方法是正确的,但我想我会在Haskell中进行练习。以下就是我所拥有的。
import qualified Data.Set as Set
substr :: String -> Int -> Int -> String
substr s start end = take (end - start) . drop start $ s
substrs :: String -> Set.Set (Char, String)
substrs s = let len = length s
in foldl (\acc x -> Set.insert (s !! x, ((substr s 0 x)++(substr s (succ x) len))) acc) Set.empty [0..len-1]
-- not sure about the type
permute [] = Set.empty
permute s = Set.map recurFunc (substrs s)
where recurFunc (c, s) = Set.map (c:) (permute s)
main :: IO ()
main = print $ permute "foo!"
当然,这不会编译,或者我不会问。我明白了:
permute.hs:12:21:
Couldn't match expected type `String'
with actual type `Set.Set [Char]'
Expected type: (Char, String) -> String
Actual type: (Char, String) -> Set.Set [Char]
In the first argument of `Set.map', namely `recurFunc'
In the expression: Set.map recurFunc (substrs s)
Set.map
被声明为(a -> b) -> Set a -> Set b
。据我所知,recurFunc
采用一组(Char, String)
对,并返回一组字符串。 substrs
会返回一组(Char, String)
对。那么这是如何不一致的?
答案 0 :(得分:6)
快速说明:type String = [Char]
。
Set.map
采用普通函数并将其映射到集合上。由于您有Set (Char, String)
并且想要Set String
,因此此函数的类型应为(Char, String) -> String
。
但是,您的recurFunc
会返回集,而不仅仅是字符串。也就是说,它的类型为(Char, String) -> Set String
。 (我认为类型实际上有点一般,但这并不重要。)因此,当您将它映射到一个集合时,您会得到一组集合:类似Set (Set String)
。
这是您的错误以略微倾斜的方式说的:它预期Set String
但得到Set (Set String)
。但是,由于错误大约是recurFunc
,因此它只会告诉您该函数的问题:Set String
应该只是String
。
希望这能为您提供足够的信息来解决您的错误。
答案 1 :(得分:1)
使用String
s只是Char
列表的事实,您可以快速写出来:
import Data.List
permute = Eq a => [a] -> [[a]]
permute = nub . permutations
预定义的permutations
实际上可以完成您想要的所有工作,nub
只会删除重复项。
请注意,这种方法效果不是很好( O(n ^ 2)),只能用于少量数据!