Haskell 根据给定的输入创建一个 n 元元组
Haskell create an n-ary tuple from given input
直截了当地说,我是 Haskell 的新手,正在尝试解决一个问题(编程练习)我过来了。它说我应该创建一个函数
com :: Int -> [t] -> [[t]]
即returns n 个元素的所有可能选择,其中 n 和 list 分别是第一个和第二个参数。可以以不同的顺序重新拾取元素。结果如下:
com 2 [1,2,3] = [[1,1], [1,2]..[3,3]]
对于案例n = 1和n = 2,我设法解决了案例。 n = 1 的情况非常简单,对于 n = 2 的情况,我会使用连接并构建它。但是,我不明白如何将它变为 n 元并适用于所有 n。就像突然一个函数调用就像 com 10
...
首先:[]
是一个列表构造器,不是一个元组。我不知道构建 n 元元组的任何通用方法。
但是,坚持使用列表,如果您已经解决了 n = 1
个案例并且解决了 n = 2
个案例,请尝试用前者来表达后者。然后根据 n-1
:
推广到任何 n
com n xs = concat [map (x:) (com (n-1) xs) | x <- xs ]
一种更冗长的编写方式,但在尝试理解 List
非确定性和试图准确理解 Haskell 理解语法糖的真正含义时可能更有帮助,是编写使用 do
表示法:
com :: Int -> [a] -> [[a]]
com 0 _ = []
com 1 xs = [[x] | x <- xs]
com n xs = do
x <- xs
let ys = com (n - 1) xs
map (x:) ys
这是你想要的吗?
> sequence (replicate 3 "abc")
["aaa","aab","aac","aba","abb","abc","aca","acb","acc"
,"baa","bab","bac","bba","bbb","bbc","bca","bcb","bcc"
,"caa","cab","cac","cba","cbb","cbc","cca","ccb","ccc"]
上面利用了 sequence
在列表 monad 中构建列表列表的笛卡尔积这一事实。所以,我们可以简单地复制我们的列表 n
次,然后取产品。
(请注意上面的 "abc"
是字符列表 ['a','b','c']
的 shorthand)
所以,解决方案可能是
com n xs = sequence (replicate n xs)
或等效地,正如 Daniel Wagner 在下面指出的那样,
com = replicateM
最后一点:我确实意识到这对于实际 学习 如何编程可能不是很有帮助。事实上,我从库中提取了两个 "magic" 函数来解决这个任务。尽管如此,它还是展示了如何将问题简化为两个子问题:1) 将值复制 n
次和 2) 构建笛卡尔积。如果您不想使用该库,第二个任务本身就是一个很好的练习。您可能希望从以下开始解决该问题:
sequence :: [[a]] -> [[a]]
sequence [] = [[]]
sequence (x:xs) = ...
where ys = sequence xs
直截了当地说,我是 Haskell 的新手,正在尝试解决一个问题(编程练习)我过来了。它说我应该创建一个函数
com :: Int -> [t] -> [[t]]
即returns n 个元素的所有可能选择,其中 n 和 list 分别是第一个和第二个参数。可以以不同的顺序重新拾取元素。结果如下:
com 2 [1,2,3] = [[1,1], [1,2]..[3,3]]
对于案例n = 1和n = 2,我设法解决了案例。 n = 1 的情况非常简单,对于 n = 2 的情况,我会使用连接并构建它。但是,我不明白如何将它变为 n 元并适用于所有 n。就像突然一个函数调用就像 com 10
...
首先:[]
是一个列表构造器,不是一个元组。我不知道构建 n 元元组的任何通用方法。
但是,坚持使用列表,如果您已经解决了 n = 1
个案例并且解决了 n = 2
个案例,请尝试用前者来表达后者。然后根据 n-1
:
n
com n xs = concat [map (x:) (com (n-1) xs) | x <- xs ]
一种更冗长的编写方式,但在尝试理解 List
非确定性和试图准确理解 Haskell 理解语法糖的真正含义时可能更有帮助,是编写使用 do
表示法:
com :: Int -> [a] -> [[a]]
com 0 _ = []
com 1 xs = [[x] | x <- xs]
com n xs = do
x <- xs
let ys = com (n - 1) xs
map (x:) ys
这是你想要的吗?
> sequence (replicate 3 "abc")
["aaa","aab","aac","aba","abb","abc","aca","acb","acc"
,"baa","bab","bac","bba","bbb","bbc","bca","bcb","bcc"
,"caa","cab","cac","cba","cbb","cbc","cca","ccb","ccc"]
上面利用了 sequence
在列表 monad 中构建列表列表的笛卡尔积这一事实。所以,我们可以简单地复制我们的列表 n
次,然后取产品。
(请注意上面的 "abc"
是字符列表 ['a','b','c']
的 shorthand)
所以,解决方案可能是
com n xs = sequence (replicate n xs)
或等效地,正如 Daniel Wagner 在下面指出的那样,
com = replicateM
最后一点:我确实意识到这对于实际 学习 如何编程可能不是很有帮助。事实上,我从库中提取了两个 "magic" 函数来解决这个任务。尽管如此,它还是展示了如何将问题简化为两个子问题:1) 将值复制 n
次和 2) 构建笛卡尔积。如果您不想使用该库,第二个任务本身就是一个很好的练习。您可能希望从以下开始解决该问题:
sequence :: [[a]] -> [[a]]
sequence [] = [[]]
sequence (x:xs) = ...
where ys = sequence xs