我是Haskell的新手并且有一个任务。我必须写一个
内部>内部 - > [U] - > [U]
给定输入两个I和i以及一个列表的函数,并返回大于i且小于j的位置的元素。到目前为止我所想的是:
fromTo :: Int->Int->[u]->[u]
fromTo i j (h:t)
|i == 1 && j == length(h:t)
= (h:t)
|i /= 1
fromTo (i-1) j t
|j /= length(h:t)
fromTo i j init(h:t)
但是我得到了第二个语法错误。我也不确定我的思路是否正确。 (init返回没有最后一个元素的列表)
编辑:已更正
|i /= 1
fromTo (i-1) j (h:t)
到
|i /= 1
fromTo (i-1) j t
答案 0 :(得分:2)
修正缩进,括号和缺少=
。这个改革编译,并适用于序数和有限的非空列表:
fromTo :: Int -> Int -> [u] -> [u]
fromTo i j (h : t)
| i == 1 && j == length (h : t) = h : t
| i /= 1 = fromTo (i - 1) j t
| j /= length (h : t) = fromTo i j (init (h : t))
我认为你正在寻找类似这样的东西,自然地索引span
:
take :: Int -> [a] -> [a]
take _ [] = []
take 0 _ = []
take n (x : xs) = x : take (n - 1) xs
drop :: Int -> [a] -> [a]
drop _ [] = []
drop 0 xs = xs
drop n (_ : xs) = drop (n - 1) xs
span :: Int -> Int -> [a] -> [a]
span i j = drop i . take (j + 1)
其中
span 0 3 [0 .. 10] == [0,1,2,3]
或者,为了符合规范:
between :: Int -> Int -> [a] -> [a]
between i j = drop (i + 1) . take j
其中
between 0 3 [0 .. 10] == [1,2]
答案 1 :(得分:0)
您在=
保护条款与正文之间缺少|
。 Haskell编译器认为整个事情都是守护者,当它遇到下一个|
后卫时会感到困惑,因为它首先需要一个身体。这将编译(虽然它仍然是错误的):
fromTo :: Int -> Int -> [u] -> [u]
fromTo i j (h:t)
| i == 1 && j == length (h:t) =
(h:t)
| i /= 1 =
fromTo (i-1) j t
| j /= length (h:t) =
fromTo i j (init (h:t))
但我想说有更好的方法来编写这个功能。例如,原则上这样的函数应该在无限列表中起作用,但是使用length
使得这是不可能的。
答案 2 :(得分:0)
以下是使用递归的完整解决方案:
fromTo :: Int -> Int -> [u] -> [u]
fromTo i j xs = go i j xs []
where go i j (x:xs) rs
| i < 0 || j < 0 = []
| i > length (x:xs) || j > length (x:xs) = []
| i /= 0 = go (i - 1) j t
| j /= 1 = goo i (j -1) (rs ++ [x])
| otherwise = rs
注意:
go
是递归函数的标准Haskell习惯用法,与主级函数相比需要额外的参数。
第一个子句确保负索引导致空列表。对于超过列表大小的任何索引,第二个都是相同的。 列表必须是有限的。第三个&#34;忘记&#34;阵列的头部i
次。第四个将积累&#34; next&#34; (j - 1)
进入rs
。当所有索引都花费在&#34;&#34;并且rs
包含结果。
你可以让它在无限列表上工作。删除第二个条款。如果rs
为空,则退回xs
&#34;耗尽&#34;索引。然后功能将采取&#34;直到&#34;来自(j-1)
的{{1}}元素。