在Haskell

时间:2019-05-10 00:44:39

标签: haskell

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

例如

> replic [2,3,4,7,6]
[[2], [3,3], [4,4,4], [7,7,7,7], [6,6,6,6,6]]

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

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)

如果我想使用该程序,如何修改以获得正确的结果? 请帮我。 :(

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)

1 个答案:

答案 0 :(得分:4)

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

  1. 赋予replic类型签名和基本情况:

    replic :: [a] -> [[a]]
    replic [] = ...
    replic (x:xs) = ...
    

    如果结果只是[ [1], [2], [3], ... ]而不是[ [1], [2,2], [3,3,3], ... ],则可以将[x] : replic xs编写为递归函数体。但是,您需要创建x n 个副本,但是您无权访问任何变量n。因此,您需要以某种方式引入一个计数器。

  2. 由于replic必须带一个[a]并返回一个[[a]],因此其类型签名中没有计数器的空间,因此您可以使用额外的累积参数:

    replic :: [a] -> [[a]]
    replic = replic' 1
    
    replic' :: Int -> [a] -> [[a]]
    replic' n [] = ...
    replic' n (x:xs) = ...
    
  3. 现在您可以输入用于创建n的{​​{1}}副本的信息,因此您的x函数将很方便:

    rep

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

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

进入

[ 1, 3, 7, ... ]

使用[ [1], [3,3], [7,7,7], ... ] 是因为map对每个元素执行 same 转换,并且

map

不是相同转换的产品,因为需要 extra 信息(列表中的位置)。使用1 ~> [1] 3 ~> [3,3] 7 ~> [7,7,7] 进行此操作的唯一方法是使列表中的位置成为您要映射的函数的输入的一部分。例如,如果您必须进行转换

map

进入

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

然后您可以使用[ [1], [3,3], [7,7,7], ... ] 和您的map来做到这一点。

但是您不能使用rep来构建此[ (1,1), (3,2), (7,3), ... ]

您必须使用显式递归函数或使用map

正如其他人所建议的,(`zip` [1..])结合了zipWithmap