首页 > 解决方案 > 在 Haskell 中定义一个函数 replicat lt

问题描述

在haskell 中定义一个函数replicat 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)

标签: haskell

解决方案


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

  1. 给出replic类型签名和基本情况:

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

    如果结果是 just[ [1], [2], [3], ... ]和 not [ [1], [2,2], [3,3,3], ... ],你可以写成[x] : replic xs递归函数体。但是,您需要创建n 个的副本x,但您无权访问任何变量n。所以你需要以某种方式引入一个计数器。

  2. 由于replicmust 接受[a]并返回 an [[a]],因此其类型签名中没有空间用于计数器,因此您可以使用额外的累加参数创建一个辅助函数:

    replic :: [a] -> [[a]]
    replic = replic' 1
    
    replic' :: Int -> [a] -> [[a]]
    replic' n [] = ...
    replic' n (x:xs) = ...
    
  3. 现在您有了创建n副本的输入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], ... ]

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

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..]).

正如其他人所推荐的那样,zipWith结合mapzip.


推荐阅读