简体   繁体   English

尝试获取最后一个元素时出现Haskell错误

[英]Haskell error when trying to get the last element

So, I am trying to implement a function that, given a list of 3 elements ((Int,Int),Int) , returns True when on the second position is the same value for all 3 and False otherwise. 因此,我正在尝试实现一个函数,给定3个元素的列表((Int,Int),Int) ,当第二个位置上所有3的值相同时返回True ,否则返回False

For instance, [((1,2),7),((5,3),7),((1,9),7)] should return True and [((1,2),3),((5,3),3),((1,9),5)] should return False . 例如, [((1,2),7),((5,3),7),((1,9),7)]应该返回True[((1,2),3),((5,3),3),((1,9),5)]应该返回False

Here is my code: 这是我的代码:

bc :: [((Int,Int),Int)]
wcheck :: [((Int,Int),Int)] -> Bool
wcheck bc
   | (( fst(fst bc) == fst(snd bc) ) && ( fst(snd bc) == fst(last bc) )) = True
   | otherwise                                                           = False

And the error that I get: 和我得到的错误:

E:\\study related\Module1\week 4\ttt.hs:55:65: error:
* Couldn't match expected type `[(a, b0)]'
              with actual type `((a, b), (a, b1))'
* In the first argument of `last', namely `bc'
  In the first argument of `fst', namely `(last bc)'
  In the second argument of `(==)', namely `fst (last bc)'
* Relevant bindings include
    bc :: ((a, b), (a, b1))
      (bound at E:\\study related\Module1\week 4\ttt.hs:54:8)
    wcheck :: ((a, b), (a, b1)) -> Bool
      (bound at E:\\study related\Module1\week 4\ttt.hs:54:1)
   |
55 |  | (( fst(fst bc) == fst(snd bc) ) && ( fst(snd bc) == fst(last bc) )) = True
   |

Could you please tell me why I get this error and a way to fix it? 您能否告诉我为什么会出现此错误以及解决方法? Thank you. 谢谢。

It will probably be easier if we perform simple pattern matching instead of using fst :: (a, b) -> a , etc. 如果我们执行简单的模式匹配而不是使用fst :: (a, b) -> afst :: (a, b) -> a可能会更容易。

Second item of the first item of the tuple 元组的第一项的第二项

We can use a pattern ((_, x), _) to obtain the second element from such 2-tuple wrapped in a 2-tuple. 我们可以使用模式((_, x), _)从包裹在2元组中的2元组中获取第二个元素。

So we can use pattern matching like: 因此我们可以使用模式匹配,例如:

wcheck :: [((Int,Int),Int)] -> Bool
wcheck [((_, x), _), ((_, y), _), ((_, z), _)] = x == y && y == z
wcheck _ = False

So here if the list contains three elements, we unpack the elements, and then check if the "second item"s are equal to each other. 因此,如果列表中包含三个元素,则我们将这些元素解包,然后检查“第二个项目”是否彼此相等。 In case the pattern does not match (for a list with too few, or too much elements), we just return False . 如果模式不匹配(对于元素太少或太多的列表),我们只返回False

But a "list of three elements" does not make much sense. 但是,“三个要素的清单”没有多大意义。 In case the number of elements is known at compile time, it is better to use a tuple, since in that way, the compiler can verify that you can only provide 3-tuples to that function. 如果在编译时知道元素的数量,则最好使用元组,因为这样,编译器可以验证您只能为该函数提供3元组。

Second item of the tuple 元组的第二项

In case we are interested in the second item of the tuple, we can use (_, x) as pattern (we are not interested in the first item whatsoever): 如果我们对元组的第二项感兴趣,可以使用(_, x)作为模式(我们对第一项不感兴趣):

wcheck :: [((Int,Int),Int)] -> Bool
wcheck [(_, x), (_, y), (_, z)] = x == y && y == z
wcheck _ = False

Note that we can generalize the signature with: 请注意,我们可以通过以下方式概括签名:

wcheck :: Eq c => [((a, b), c)] -> Bool
wcheck [(_, x), (_, y), (_, z)] = x == y && y == z
wcheck _ = False

fst and snd are not very nice in this situation. 在这种情况下, fstsnd不太好。 We can extract the bit we care about by doing a pattern match: 我们可以通过进行模式匹配来提取我们关心的部分:

let (_,y) = x in ...

Now you want to do that to each element of your list (to check that every element has the same second value): 现在,您要对列表中的每个元素执行此操作(以检查每个元素具有相同的第二个值):

map (\(_,x) -> x)

And then you want to check that they are all equal: 然后,您要检查它们是否相等:

allEqual :: Eq a => [a] -> Bool
allEqual [] = True
allEqual (x:xs) = all (\y->x==y) xs

This gets the first element, x , from a list (if it exists) and checks that ever other item y satisfies the test that x==y 这将从列表(如果存在)中获取第一个元素x ,并检查是否其他项y满足x==y的检验

So we can now write your function: 现在我们可以编写您的函数了:

wcheck xs = allEqual (map (\(_,y) -> y) xs)

Given that you want to test the equality of the second element of the outer pair, there are so many ways to do this, including the following. 假设您要测试外部对中第二个元素的相等性,那么有很多方法可以做到这一点,包括以下内容。

First, fmapping snd gives you these elements: 首先,将snd映射会为您提供以下元素:

λ> fmap snd [((1,2),7),((5,3),7),((1,9),7)]
[7,7,7]

Now you can group them to lists of consecutive equal numbers: 现在,您可以将它们分组到连续相等的数字列表中:

λ> import Data.List
λ> (group . fmap snd) [((1,2),7),((5,3),7),((1,9),7)]
[[7,7,7]]

The values are equal if the length of this list of lists is at most one (assuming an empty list of such pairs is defined to have equal second elements): 如果此列表列表的长度最多为1,则这些值相等(假设将这样的对的空列表定义为具有相等的第二个元素):

λ> (length . group . fmap snd) [((1,2),7),((5,3),7),((1,9),7)]
1

Putting these together we can define 将这些放在一起,我们可以定义

import Data.List

equalSnds :: Eq a => [(b, a)] -> Bool
equalSnds xs = (length . group . fmap snd) xs <= 1

So that 以便

λ> equalSnds [((1,2),7),((5,3),7),((1,9),7)]
True
λ> equalSnds [((1,2),3),((5,3),3),((1,9),5)]
False

If you want to also test for the length of the list, you can do it separately: 如果您还想测试列表的长度,可以单独进行:

wcheck :: [((Int,Int),Int)] -> Bool
wcheck xs = length xs == 3 && equalSnds xs

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

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