如何使用haskell中的递归函数查找列表的第n个元素?还有更多

如何使用haskell中的递归函数查找列表的第n个元素?还有更多,haskell,functional-programming,Haskell,Functional Programming,我最近开始在Haskell学习函数编程,有人给了我一些需要解决的问题,它要求为使用递归和基本系统函数的列表制作自己版本的一些系统函数。我需要编写的函数是: (列表中的第n项) 追加(将列表合并在一起) subst(替换)例如subst'x'y'['q','x','r','x','s']~>['q','y','r','x','y','s'] 交叉口例如交叉口[2,5,7][9,7,3,5]~>[5,7] unionunion例如union[2,5,7][9,7,3,5]~>[2,5,7,9,3]

我最近开始在Haskell学习函数编程,有人给了我一些需要解决的问题,它要求为使用递归和基本系统函数的列表制作自己版本的一些系统函数。我需要编写的函数是:

  • (列表中的第n项)
  • 追加
    (将列表合并在一起)
  • subst
    (替换)例如
    subst'x'y'['q','x','r','x','s']
    ~>
    ['q','y','r','x','y','s']
  • 交叉口
    例如
    交叉口[2,5,7][9,7,3,5]
    ~>
    [5,7]
  • union
    union例如
    union[2,5,7][9,7,3,5]
    ~>
    [2,5,7,9,3]
  • 反向
    例如
    反向[4,5,6,7]
    ~>
    [7,6,5,4]
我从第一个开始写了一个这样的定义:

nthelement :: Eq a => [a] -> a -> a
在命令式语言中,我将生成一个计数器变量(比如
i
),并使用系统函数
tail
删除列表的第一个元素,直到
i=n
。但正如我所了解到的,在函数中,你只能执行常量,我想不出一种方法来决定何时停止循环并返回元素,而不是在列表为空之前重复执行
tail
函数

请帮我弄清楚这件事。任何关于做第一个函数或其中任何一个的帮助都是非常好的。谢谢。

(正如@Bergi在评论中正确指出的,您应该检查您的签名与标准库中的
!!
中的签名是否一致!)

不要想着
列表中的
i
!!i
作为变量,将其视为函数参数。然后,考虑这个参数的不同情况,并决定你的<代码>!!<代码>函数在每种情况下都应该执行。然后,考虑列表参数<代码>清单>代码>的选项,以及如何考虑它们:

扩展
i
list
的所有潜在选项,我们可以得到以下信息:

nthelement :: [a] -> Integer -> a
nthelement [] 0 = -- ?
nthelement [] i = -- ?
nthelement (l:ls) 0 = -- ?
nthelement (l:ls) n = -- ?

其余的函数可以按照类似的策略编写。

这里我只是对您提出的一个问题提供一个一般性的答案。我希望这将帮助您更好地理解一般问题,并为您的具体问题/任务提出解决方案

在命令式语言中,我将生成一个计数器变量(比如i),并使用系统函数tail删除列表的第一个元素,直到i=n。但正如我所了解到的,在函数中,你只能做常量,我想不出一种方法来决定什么时候停止循环并返回元素,而不是循环尾部函数直到列表为空

您始终可以使用状态变量“模拟”for循环,并使用递归中断循环:

Python:

def foo(xs):
状态=初始状态
对于xs中的x:
状态=创建新状态(x,状态)
如果不是条件(状态,x):
打破
返回状态
在等价的Haskell代码中,您将使用一个内部函数和一个额外的状态参数。您还可以在
foo
上公开额外的参数,但通常不希望将其公开给
foo
的调用者:

foo xs=go initialState xs
where go[]state=state
go(x:xs)状态=如果不是(条件状态x)
然后陈述
else go xs(makeNewState x状态)
对于许多算法,根本不需要打破循环,在这种情况下,“模式”变成:

foo xs=go initialState xs
where go[]state=state
go(x:xs)状态=go xs(makeNewState x状态)
其中,
makeNewState
是您在每个步骤中执行的逻辑(当然,它不必位于单独的函数中)

对于后一种情况,有一些通用函数
foldr
foldl
foldl'
,例如:

foo xs=foldr makeNewState initialState xs


此外:还有类似的功能,可以让您以纯粹的方式编写命令式逻辑,但最好先了解“原始”递归和折叠,然后再了解单子和显式状态等功能。

首先从准确的类型签名开始
n元素
不需要
Eq a
,也不需要列表旁边的
a
。例如使用
ntheelement['a','c','b']1~>'c'
尝试模式匹配和标准结构递归。不要使用
head
tail
。我必须写Ord a。我的理解是:Ord a=>意味着这个函数的参数必须是有序类型(Int's,Float's,但不是Strings?)[a]->a->a意味着这个函数将接受一个列表参数,一个(Int/Float)并返回Int/Float(Ord)n元素[1,2,3]1将返回2。这里我错了吗?实际上它是
xs n=head。drop n$xs
@EasternDude:不,
Ord a
意味着
a
s是可比较的-
。你的意思是一个
Num
(算术运算)。您实际需要的是整数类型,例如
Integer
Int
。你所遇到的基本问题是,你已经将索引指定为与列表元素相同的类型。+1用于识别相关的基本情况,而不是提供完整的解决方案:-)如果我希望我的函数只处理数字列表(我知道这没有多大意义,只是为了学习目的)我会这样定义函数吗?:
ntheelement::Num a=>[a]->Int->a
@EasternDude是的,这会将列表中的元素限制为数字类型。使用
ntheelement::(Num a,Integral i)=>[a]可以使事情变得更一般化