首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Haskell:递归复制函数

Haskell:递归复制函数
EN

Stack Overflow用户
提问于 2015-06-21 05:08:57
回答 3查看 5.6K关注 0票数 3

我才刚刚开始接触Haskell。我正在尝试创建一个函数,它模仿Haskell中的标准replicate函数,但使用了递归。例如,

代码语言:javascript
复制
Prelude> replicate 3 "Ha!"
["Ha!","Ha!","Ha!"]

它的类型应该是Int -> a -> [a]。到目前为止,我有:

代码语言:javascript
复制
myReplicate :: Int -> a -> [a]
myReplicate x y = y : myReplicate (x-1) y
myReplicate 0 y = [ ]

但是,我的函数总是生成无限列表:

代码语言:javascript
复制
Prelude> myReplicate 3 "Ha!"
["Ha!","Ha!","Ha!","Ha!","Ha!","Ha!","Ha!",...
EN

回答 3

Stack Overflow用户

发布于 2015-06-21 05:16:04

你必须把第二个案例放在第一个案例之前,否则它永远不会到达第二个案例。

代码语言:javascript
复制
myReplicate :: Int -> a -> [a]
myReplicate 0 y = [ ]
myReplicate x y = y : myReplicate (x-1) y
票数 9
EN

Stack Overflow用户

发布于 2015-06-21 05:24:43

您的代码应该生成一个警告读数(至少在GHC中):

代码语言:javascript
复制
Pattern match(es) are overlapped
In an equation for 'myReplicate': myReplicate 0 y = ...

发生的情况是,代码试图按照您编写的顺序(从上到下)将您的输入与您编写的每个定义进行匹配。当您编写f x = ...时,x变量将始终与它所表示的类型的任何值匹配。如果定义中的所有绑定都匹配,则将使用该定义。

在您的示例中,第一个定义是myReplicate x y = y : myReplicate (x-1) y。正如我所说的,xy将与您传递的任何值匹配,包括用于x绑定的0。@Alec提出的解决方案展示了如何避免这个问题,首先编写最具体的模式,最后编写通用模式。

另一种解决方案是使用卫士:

代码语言:javascript
复制
myReplicate :: Int -> a -> [a]
myReplicate x y
    | x > 0  = y : myReplicate (x-1) y
    | x == 0 = []
    | otherwise = [] -- or throw an exception, or use Maybe

这样,如果您正确地编写了条件(换句话说,如果这些条件是互斥的),您就可以以任何顺序编写要使用的表达式。注意,条件仍将首先从上到下计算,然后向下计算,直到条件为真,这非常类似于命令式语言中的if ... else if ... else if ... else ...链。

票数 5
EN

Stack Overflow用户

发布于 2020-02-09 05:23:04

您可以使用map:

代码语言:javascript
复制
myReplicate :: Int -> a -> [a]
myReplicate n x = map (const x) [1..n]

您也可以从Data.Functor使用$>

代码语言:javascript
复制
import Data.Functor 
myReplicate :: Int -> a -> [a]
myReplicate n x = [1..n] $> x
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30958914

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档