Фильтрация пользовательского кортежа в haskell - PullRequest
0 голосов
/ 16 апреля 2020

Эй, ребята, я работаю над функцией, которая выводит настольную игру в виде строки. В настоящее время у меня это работает, так что я могу вывести доску без каких-либо частей.

Я пытаюсь добавить фильтр, чтобы, если текущая (x, y) координата была в списке кортежей [Position, Col], где Position - это (Int, Int).

Если в этом списке есть (x, y), я хочу проверить цвет Col и затем вывести соответственно.

drawBoardCell :: (Int, Int) ->[(Position, Col)] -> String
drawBoardCell (x, y) pieces = do
      let test = filter (\((a,b),_) -> a == x && b == y) pieces
      if snd(test) == Black
            then " b "
      else if snd(test) == White
            then " w "
      else " . "

Это то, что у меня есть попробовал до сих пор и столкнулся с ошибкой:

Display.hs:47:14: error:
    • Couldn't match expected type ‘(a0, Col)’
                  with actual type ‘[((Int, Int), Col)]’
    • In the first argument of ‘snd’, namely ‘(test)’
      In the first argument of ‘(==)’, namely ‘snd (test)’
      In the expression: snd (test) == Black

Display.hs:49:19: error:
    • Couldn't match expected type ‘(a1, Col)’
                  with actual type ‘[((Int, Int), Col)]’
    • In the first argument of ‘snd’, namely ‘(test)’
      In the first argument of ‘(==)’, namely ‘snd (test)’
      In the expression: snd (test) == White

Ответы [ 2 ]

1 голос
/ 16 апреля 2020

filter возвращает список, но snd ожидает кортеж. Это разные типы.

Вы можете настроить условное выражение как

      if snd(head test) == Black
            then " b "
      else if snd(head test) == White
            then " w "
      else " . "

, но что если test - это пустой список, []?

Вы можете закодировать это как

      if not (null test) && snd(head test) == Black
            then " b "
      else not (null test) && if snd(head test) == White
            then " w "
      else " . "

, но это не очень приятно Haskell. Вместо этого мы можем получить немного лучший код с сопоставлением с шаблоном :

      case  test  of
        ((_,Black):_) -> " b "
        ((_,White):_) -> " w "
        _             -> " . "

или реструктурировать ваш код, чтобы использовать

find :: (a -> Bool) -> [a] -> Maybe a

вместо

filter :: (a -> Bool) -> [a] -> [a]

Вы можете использовать Hoogle , чтобы узнать больше.

0 голосов
/ 16 апреля 2020

Проблема в том, что test по-прежнему является списком [(Position, Col)], поэтому его нельзя передать в snd, который ожидает один кортеж (a, b). Если вы можете гарантировать, что в вашем массиве кусков будет совпадение, вы должны изменить свое тело на:

drawBoardCell (x, y) pieces =
  let [match] = filter (\((a,b),_) -> a == x && b == y) pieces
  case match of
    (_, Black) -> " b "
    (_, White) -> " w "
    _          -> " . "

Обратите внимание на использование case здесь вместо if. В этом нет особой необходимости, но он более понятен при сравнении значения с несколькими вариантами для сопоставления таким образом.

Если, однако, как я подозреваю, так, у вас может быть 0 или 1 совпадение, вам нужно использовать что-то вместо этого:

drawBoardCell (x, y) pieces = do
  case filter (\((a,b),_) -> a == x && b == y) pieces of
    [(_, Black)] -> " b "
    [(_, White)] -> " w "
    _            -> " . "

Это выведет " . ", если значение не присутствует в отфильтрованном списке, если значение присутствует несколько раз, или если Col одного совпадения равно ни White, ни Black.

В комментариях указывается, что вы можете по-разному обрабатывать отсутствие совпадений и множественных совпадений. В этом случае:

drawBoardCell (x, y) pieces = do
  case filter (\((a,b),_) -> a == x && b == y) pieces of
    [(_, Black)] -> " b "
    [(_, White)] -> " w "
    []           -> " . "  -- Case of no matches
    _            -> error "Multiple pieces cannot occupy the same position " ++ show (x, y)

Этот пример вызовет ошибку времени выполнения, если список содержит несколько совпадений (что может быть полезно для отладки).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...