简体   繁体   English

如何逐个元素地遍历列表

[英]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 ,它接受一个列表和一个IntN )作为参数并返回列表中索引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 give 4 and not 3 .例如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 == 1xs == [2, 3, 4]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM