我在一个问题上找到了这段代码,这个问题类似于我试图解决的问题,并且我试图将此函数的逻辑应用于我的问题。但是,代码的解释在这个问题上并不完全清楚。代码如下:
splitAtIndex :: Int -> [a] -> ([a], [a])
splitAtIndex 0 xs = ([], xs)
splitAtIndex _ [] = ([], [])
splitAtIndex x (y:ys) = (y:ys', ys'')
where
(ys', ys'') = splitAtIndex (x - 1) ys
我理解这一点的方法是,你获取索引和整个列表并形成一个列表元组,其中列表的元组等于列表尾部的索引-1的递归调用。我在这里错过了什么吗?撇号的使用在这里很重要吗?我真的不知道列表的拆分发生在哪里。我确信一旦解释它看起来很简单,但我似乎无法掌握它。
谢谢!
答案 0 :(得分:1)
正如已经指出的那样,撇号相当于名字中的字母。惯例是,如果您有一个变量x
,那么修改后的x副本通常称为x'
。
为消除这种混淆,您可以将定义重写为:
splitAtIndex x (y:ys) = (y:p, q) where (p, q) = splitAtIndex (x - 1) ys
要理解算法,考虑一个例子可能会有所帮助。我们假设您要将列表[1,2,3,4,5,6]拆分为位置2.呼叫将是:
splitAtIndex 2 [1,2,3,4,5,6]
函数中的where
子句产生以下表达式:
splitAtIndex 1 [2,3,4,5,6]
因为ys
是尾部而(x-1)
是(2-1)。该表达式的结果是元组(p,q)
。但是原始表达式的结果将原始列表的第一个元素聚合到元组(y:p,q)
的第一个元素上。因此splitAtIndex 2 [1,2,3,4,5,6]
的结果是(1:p, q)
,其中p
是splitAtIndex 1 [2,3,4,5,6]
的第一个元素,q
是该元组的第二个元素。我们希望splitAtIndex 1 [2,3,4,5,6]
返回([2],[3,4,5,6])
,最终结果为(1:[2],[3,4,5,6])
(([1,2],[3,4,5,6])
。
答案 1 :(得分:0)
撇号属于用于递归调用splitAtIndex (x - 1) ys
的变量。这是唯一的含义。
当你开始思考指数为1时,你可以理解代码。在这里你取出元组左边的空列表,并在列表的左边悬挂。等等。