在Haskell中定义函数replic lt

在Haskell中定义函数replic lt,haskell,Haskell,在haskell中定义一个函数replic lt,将lt中的每个元素复制到列表中。如果元素位于lt的第k个位置,则生成的列表包含同一元素的k个副本。必须使用map的高阶函数定义此函数 例如 我的方法很简单,但存在一些问题: maps f [] = [] maps f (x:xs) = f [x] : maps f xs rep a b |b==0 = [] |b<0 = error "negative value" |otherwise = a ++ rep a (b-1)

在haskell中定义一个函数replic lt,将lt中的每个元素复制到列表中。如果元素位于lt的第k个位置,则生成的列表包含同一元素的k个副本。必须使用
map
的高阶函数定义此函数

例如

我的方法很简单,但存在一些问题:

maps f [] = []
maps f (x:xs) = f [x] : maps f xs

rep a b
  |b==0 = []
  |b<0 = error "negative value"
  |otherwise = a ++ rep a (b-1)

replicas []=[]
replicas (x:xs) = rep (x:xs) xs

replic (x:xs) = maps replicas (x:xs)
映射f[]=[]
映射f(x:xs)=f[x]:映射f-xs
代表a b
|b==0=[]

|b您可以使用显式递归解决问题,然后尝试检测可以用高阶函数替换递归的某些部分的位置。以下是创建显式递归版本的一些提示:

  • replic
    一个类型签名和一个基本大小写:

    replic :: [a] -> [[a]]
    replic [] = ...
    replic (x:xs) = ...
    
    如果结果只是
    [[1],[2],[3],…]
    ,而不是
    [[1],[2,2],[3,3],…]
    ,则可以编写
    [x]:replic xs
    作为递归函数体。但是,您需要创建n个
    x
    副本,但您无权访问任何变量
    n
    。所以你需要引入一个计数器

  • 由于
    replic
    必须接受
    [a]
    并返回
    [[a]]]
    ,因此其类型签名中没有计数器的空间,因此您可以创建一个带有额外累积参数的帮助器函数:

    replic :: [a] -> [[a]]
    replic = replic' 1
    
    replic' :: Int -> [a] -> [[a]]
    replic' n [] = ...
    replic' n (x:xs) = ...
    
  • 现在您有了创建
    n
    x
    副本的输入,因此您的
    rep
    功能将派上用场:

    rep :: a -> Int -> [a]
    rep x n
      | n > 0  = x : rep x (n-1)
      | otherwise = []
    

  • 至于用高阶函数来解决这个问题,转换起来有点困难

    [ 1, 3, 7, ... ]
    
    [ (1,1), (3,2), (7,3), ... ]
    
    进入

    使用
    map
    ,因为
    map
    对每个元素执行相同的转换,并且

    1 ~> [1]
    3 ~> [3,3]
    7 ~> [7,7,7]
    
    不是相同转换的产品,因为需要额外的信息(列表中的位置)。使用
    map
    可以做到这一点的唯一方法是将列表中的位置作为要映射的函数输入的一部分。例如,如果您必须转换

    [ 1, 3, 7, ... ]
    
    [ (1,1), (3,2), (7,3), ... ]
    
    进入

    然后,您可以使用
    map
    rep
    执行此操作

    但是您不能使用
    映射构建此
    [(1,1)、(3,2)、(7,3),…])

    您必须使用显式递归函数或使用
    (`zip`[1..])
    执行此操作


    正如其他人所建议的那样,
    zipWith
    结合了
    map
    zip

    到目前为止您尝试了什么?养成为函数提供类型签名的习惯是很好的。您在这里犯了几个错误,我认为如果您已经给出了每个函数的类型签名,您会更容易看到这些错误。尝试为每个
    映射
    rep
    副本
    replic
    提供您认为它们应该具有的签名,并查看由此产生的错误是否解决了您的任何问题。如果您不更新问题中的代码,则无法帮助您解决错误。您肯定没有从那里的代码中得到错误。@user11228628,您为什么建议使用
    zip
    而不是
    zipWith
    ?这里显而易见的解决方案是直接应用
    zipWith
    @dfeuer,只是因为OP反复指定必须涉及
    map
    。在第二条评论中,OP表示她知道直接的
    zipWith
    解决方案,但由于它不使用
    map
    ,所以不会这样做。
    [ (1,1), (3,2), (7,3), ... ]
    
    [ [1], [3,3], [7,7,7], ... ]