Haskell 创建映射操作,使每个输入元素生成1个或多个输出元素?
最近,我试图找出如何在Haskell中进行一些编程 我想做一些简单的操作。现在,我遇到了一个类似于本例的操作:Haskell 创建映射操作,使每个输入元素生成1个或多个输出元素?,haskell,Haskell,最近,我试图找出如何在Haskell中进行一些编程 我想做一些简单的操作。现在,我遇到了一个类似于本例的操作: input = [1,2,3,4] output = [1,2,2,3,3,3,4,4,4,4] 也就是说,对于input中的每个元素x,在output中生成x元素。因此,对于输入中的元素1,将[1]附加到输出中。然后,对于输入中的元素2,将元素[2,2]附加到输出。然后,对于元素3,添加[3,3,3]等。该算法应仅适用于标准数字 我知道这很容易,在“普通”命令式编程中执行它也很简单
input = [1,2,3,4]
output = [1,2,2,3,3,3,4,4,4,4]
也就是说,对于input
中的每个元素x
,在output
中生成x
元素。因此,对于输入中的元素1
,将[1]
附加到输出中。然后,对于输入中的元素2
,将元素[2,2]
附加到输出。然后,对于元素3
,添加[3,3,3]
等。该算法应仅适用于标准数字
我知道这很容易,在“普通”命令式编程中执行它也很简单,但由于Haskell的函数是无状态的,我在如何处理这一点上遇到了问题
有谁能给我一些提示,一个绝对的哈斯克尔初学者如何应对这个问题?你刚刚发现了单子 以下是您所做工作的总体思路: 对于输入中的每个
a
-元素(即容器类型ma
,此处[a]
),您可以指定一个完整的新容器mb
。但最终的结果是,您只需要一个“扁平”容器mb
>让我们看一下<代码> Monad < /Cord>类类的定义:
class (Applicative m) => Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
这正是你需要的。和列表是Monad的一个实例,因此您可以编写
replicates :: [Int] -> [Int]
replicates l = l >>= \n -> replicate n n
或者,这可以写下来
replicates l = do
n <- l
replicate n n
复制l=do
n=\\->返回n
。。。或者至少在GHC的一些旧版本中,我认为它现在使用了更优化的列表理解实现。您仍然可以使用
-XMonadComprehensions
标志启用该脱糖变体。作为初学者,我更容易理解以下内容:
concat$map(\x->take x$repeat x)[1,2,3,4]
对于“列表为单子”,重要的是要知道在引擎盖下也有“concat”操作(在绑定定义中),IMO是另一个解决方案,利用列表理解:
output = [ n | n <- input , m <- [1..n] ]
一个简单的解决方案:
rep (x:xs) = replicate x x ++ rep xs
rep [] = []
提示:
给出了replicate 5“a”
,它对第二个参数中的任何类型都起相同的作用,但第一个参数必须是Int类型[“a”、“a”、“a”、“a”]
- 运算符
连接两个列表++
- 因此,
的推断类型是rep
,如果需要使用其他类型,则应使用转换函数[Int]->[Int]
take x$repeat x
只是replicate x
concat$map…
通常写为concatMap…
,或者使用列表单子表示法,[1..4]>=(\x->replicate x)
(后者有很好的“处理器”感觉,但YMMV)。pointfree的狂热者可能会将最后一个写为。
output = [ n | n <- input , m <- [1..n] ]
for n in input: -- n <- input
for m in range(1,n+1): -- m <- [1..n] (in Python the second extreme is excluded, hence +1)
print n -- the n in [ n | ... ]
output = [ n | n <- input , _ <- [1..n] ]
rep (x:xs) = replicate x x ++ rep xs
rep [] = []