[英]How to iterate through a list, element by element
I have just started learning Haskell and I am trying to write some basic functions in order to get a better understanding of this language.我刚刚开始学习 Haskell 并且我正在尝试编写一些基本功能以便更好地理解这种语言。
I want to write a function which takes a list and an Int
( N
) as argument and returns the element at index N
in the list, without using the !!
我想写一个 function ,它接受一个列表和一个Int
( N
)作为参数并返回列表中索引N
处的元素,而不使用!!
operator or any built-in function.运算符或任何内置的 function。
Here is what I tried:这是我尝试过的:
myHead :: [a] -> a
myHead (x:_) = x
myHead [] = error "head: empty list"
myNth :: [a] -> Int -> a
myNth x i = if i < 0
then error "nth: index can't be negative"
else myNthIterator x i 0
myNthIterator :: [a] -> Int -> Int -> a
myNthIterator [] i n = error "nth: bad index"
myNthIterator (_:x) i n = if i == n
then myHead x
else myNthIterator x i ( n + 1 )
It works but it's shifted to the right.它有效,但它向右移动。 For example myNth [1, 2, 3, 4] 2
would give 4
and not 3
.例如myNth [1, 2, 3, 4] 2
会给出4
而不是3
。
From what I understand, (_:x)
removes the first element of the list and I don't see how to iterate through the list element by element.据我了解, (_:x)
删除了列表的第一个元素,我看不到如何逐个元素地遍历列表元素。
Could someone put me on the trail?有人可以让我上路吗? I find it difficult to find resources for beginners in this language.我发现很难为这种语言的初学者找到资源。
We can use Maybe
to model whether the index was valid.我们可以使用Maybe
来 model 索引是否有效。
nth :: Int -> [a] -> Maybe a
nth 0 (x : _) = Just x
nth n (x : xs) = nth (n - 1) xs
nth _ [] = Nothing
We can pattern match on the index to get our base case, and the list to get the first element and tail.我们可以在索引上进行模式匹配以获取我们的基本情况,并在列表上获取第一个元素和尾部。
What you're doing there with (_:x)
is called "pattern matching" in case you didn't know.如果您不知道,您在(_:x)
那里所做的事情称为“模式匹配” 。 The general pattern for iterating through a list would be (x: xs)
where x
is head element of the list being matched and xs
is the rest of the list.遍历列表的一般模式是(x: xs)
,其中x
是要匹配的列表的头元素, xs
是列表的 rest。 If you use _
you don't remove anything it is still matched to _
which is the convention for saying "I won't use this".如果你使用_
你不会删除任何它仍然匹配_
这是说“我不会使用这个”的约定。
With that you can make a function like this:有了它,您可以像这样制作 function:
myNth :: [a] -> Int -> a
myNth [] _ = error "out of range"
myNth (x : xs) 0 = x
myNth (_ : xs) n = myNth xs (n - 1)
Whenever myNth
is called it will go top to bottom over those definitions trying to match the patterns to the input.每当调用myNth
时,它将 go 从上到下覆盖那些试图将模式与输入匹配的定义。 So when you call myNth [10,11] 1
it won't match the first clause because [10,11]
doesn't match an empty list, it won't match the second either because 1
is not 0
and so it will match the third case where it will match the [10,11]
on (10: [11])
, therefore _
is 10
and xs
is [11]
and 1
will be matched as n
.因此,当您调用myNth [10,11] 1
时,它不会匹配第一个子句,因为[10,11]
不匹配一个空列表,它也不会匹配第二个子句,因为1
不是0
,所以它会匹配第三种情况,它将匹配(10: [11])
上的[10,11]
,因此_
是10
并且xs
是[11]
并且1
将匹配为n
。 Then it calls itself recursively, as myNth [11] 0
.然后它递归地调用自己,如myNth [11] 0
。 Now that will match the second case and it will return x
from the match of [11]
on (11: [])
现在它将匹配第二种情况,它将在(11: [])
上从[11]
的匹配中返回x
Like 414owen said you can use the Maybe a
type to avoid using error
.就像 414owen 说的,你可以使用Maybe a
类型来避免使用error
。
PS: I don't know how beginner you are but I assume you know of the :
operator, it prepends an element to a list... If you go more in depth (afaik) every list is actually stored as a sequence of a:(b:(c:(d:(e:[]))))
which is equivalent to [a,b,c,d,e]
which is equivalent to a:[b,c,d,e]
etc. PS:我不知道您是多么初学者,但我假设您知道:
运算符,它将一个元素添加到列表中...如果您 go 更深入(afaik),每个列表实际上都存储为a:(b:(c:(d:(e:[]))))
序列a:(b:(c:(d:(e:[]))))
相当于[a,b,c,d,e]
相当于a:[b,c,d,e]
等.
It works but it's shifted to the right.它有效,但它向右移动。 For example
myNth [1, 2, 3, 4] 2
would give4
and not3
.例如myNth [1, 2, 3, 4] 2
会给出4
而不是3
。
myNthIterator (_:x) in = if i == n then myHead x else myNthIterator xi ( n + 1 )
Let us look at myNthIterator [1..4] 1 1
让我们看看myNthIterator [1..4] 1 1
myNthIterator [1..4] 1 1 -- replace [a, b] with (a: (b : []))
== myNthIterator (1 : [2, 3, 4]) 1 1
-- matching with `myNthIterator (_:x) i n` will result in
-- 1 ~ _
-- x ~ [2, 3, 4]
-- i ~ 1
-- n ~ 1
== if 1 == 1 then myHead [2, 3, 4] else myNthIterator [2, 3, 4] 1 (1 + 1)
== myHead [2, 3, 4]
== 2
So (_:x)
matching against (1: [2, 3, 4])
is suspicious.所以(_:x)
匹配(1: [2, 3, 4])
是可疑的。 A first step in fixing it is to replace (_:x)
by (x:xs)
.修复它的第一步是将(_:x)
替换为(x:xs)
。
myNthIterator (x:xs) i n = ...
In our example this would mean x == 1
and xs == [2, 3, 4]
.在我们的示例中,这意味着x == 1
和xs == [2, 3, 4]
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.