Ошибка Haskell при попытке получить последний элемент - PullRequest
0 голосов
/ 29 сентября 2018

Итак, я пытаюсь реализовать функцию, которая, учитывая список из 3 элементов ((Int,Int),Int), возвращает True, когда во второй позиции находится одинаковое значение для всех 3 и False в противном случае.

Например, [((1,2),7),((5,3),7),((1,9),7)] должен вернуть True, а [((1,2),3),((5,3),3),((1,9),5)] должен вернуть False.

Вот мой код:

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

И ошибка, которую я получаю:

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
   |

Не могли бы вы сказать мне, почему я получаю эту ошибку и способ ее исправить?Спасибо.

Ответы [ 3 ]

0 голосов
/ 29 сентября 2018

fst и snd не очень хороши в этой ситуации.Мы можем извлечь интересующий нас бит, выполнив сопоставление с образцом:

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

Теперь вы хотите сделать это для каждого элемента вашего списка (чтобы убедиться, что каждый элемент имеет одинаковое второе значение):

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

И затем вы хотите проверить, что все они равны:

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

Это получает первый элемент, x, из списка (если он существует) и проверяет, что когда-либодругой элемент y удовлетворяет критерию, который x==y

Итак, теперь мы можем написать вашу функцию:

wcheck xs = allEqual (map (\(_,y) -> y) xs)
0 голосов
/ 29 сентября 2018

Учитывая, что вы хотите проверить равенство второго элемента внешней пары, существует множество способов сделать это, включая следующие.

Во-первых, fmapping snd дает вам следующие элементы:

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

Теперь вы можете сгруппировать их в списки последовательных равных чисел:

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

Значения равны, если длина этого списка списков не более одного (при условии, что пустойсписок таких пар определен, чтобы иметь равные вторые элементы):

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

Собрав их вместе, мы можем определить

import Data.List

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

Так что

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

Если выХотите также проверить длину списка, вы можете сделать это отдельно:

wcheck :: [((Int,Int),Int)] -> Bool
wcheck xs = length xs == 3 && equalSnds xs
0 голосов
/ 29 сентября 2018

Вероятно, будет проще, если мы выполним простое сопоставление с шаблоном вместо использования fst :: (a, b) -> a и т. Д.

Второй элемент первого элемента кортежа

Мы можем использовать шаблон ((_, x), _) для получения второго элемента из такого 2-кортежа, обернутого в 2-кортеж.

Таким образом, мы можем использовать сопоставление с шаблоном, например:

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

Так что здесьесли список содержит три элемента, мы распаковываем элементы, а затем проверяем, равны ли «вторые элементы» друг другу.Если шаблон не совпадает (для списка, содержащего слишком мало или слишком много элементов), мы просто возвращаем False.

Но «список из трех элементов» не имеет особого смысла.Если число элементов известно во время компиляции, лучше использовать кортеж, так как таким образом компилятор может проверить, что вы можете предоставить только 3 кортежа для этой функции.

Второй элементкортеж

В случае, если нас интересует второй элемент кортежа, мы можем использовать (_, x) в качестве шаблона (нас не интересует первый элемент вообще):

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

Обратите внимание, что мы можем обобщить подпись с помощью:

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