как представить `n` в виде ряда чисел

#list #variables #haskell #types

#Список #переменные #haskell #типы

Вопрос:

У меня есть следующая функция:

 type Coordin = (Int,Int)

data Grid = Open
          | Taken Int

myOwn :: Coordin -> Grid -> Bool
myOwn (x,y) grid  
    | ((board)!!(y)!!(x)) == Taken n           = True
    | otherwise                                = False
  

Я хотел бы n иметь в виду любое число (как Int указано как таковое в таблице данных для этого конкретного типа), но это просто не сработает!! Я думал об использовании where предложения, но если есть какие-либо другие идеи, это было бы очень ценно. Спасибо.

Ответ №1:

С вдохновением формируйте решение camccann:

 type Board = [[Grid]]

isTaken :: Grid -> Bool
isTaken (Taken _) = True
isTaken Open      = False

myOwn :: Coordin -> Board -> Bool
myOwn (x,y) board = isTaken (board !! y !! x)
  

Комментарии:

1. Есть какой-нибудь способ объединить isTaken и myOwn в единую функцию?

2. @maclunian Да, но приятно разбивать вещи на небольшие функции.

3. @maclunian, подумай дважды, мой друг. Что, если вам позже снова понадобится isTaken ? Если вы объедините две функции, у вас не останется ни одной isTaken . Теперь представьте, что вы повторно используете isTaken несколько раз, а через 3 месяца меняете data Grid = , чтобы также включить конструктор ReTaken Int . Затем вы должны обновить isTaken только в одном месте вашего кода . Это модульность и причина, по которой мы любим haskell. 🙂

Ответ №2:

Выражение после защитного знака является логическим предикатом, а не привязкой к шаблону. Таким образом, вы не можете сопоставить Taken n с вычисленным значением и привязать значение к n .

По сути, защита эквивалентна этому:

 myOwn (x,y) grid = if board !! y !! x == Taken n
                   then True
                   else False
  

Помимо излишнего if утверждения, должно быть очевидно, что вы не можете привязывать n в этом контексте.

Чтобы сделать то, что вы пытаетесь, вам понадобится другое соответствие шаблону:

 myOwn (x,y) grid = case board !! y !! x of
                       Taken n -> True
                       ...
  

Но, поскольку вы на самом деле не используете здесь значение n , вам было бы лучше написать отдельную функцию:

 isTaken (Taken _) = True
isTaken Open = False
  

… затем вместо этого защищаем этим.

Кстати, со стилистической точки зрения, у вас много уродливых лишних круглых скобок в вашем выражении guard; вам следует их удалить.

Комментарии:

1. Есть ли способ, которым я мог бы объединить isTaken и myOwn в единую функцию?

2. @maclunian: Скорее всего, вы хотели бы определить, myOwn используя isTaken , как в том, что написал @Tarrasch. Но нет причин иметь единое определение, потому что isTaken и индексирование сетки — концептуально разные операции, и это более читаемо с isTaken разделением.

Ответ №3:

 myOwn (x,y) grid = not (board !! y !! x  == Open)
  

Комментарии:

1. Я надеюсь, вы не возражаете против критики, но, хотя этот ответ не является принципиально неправильным, он далек от идеала. Grid не имеет Eq экземпляра, и хотя в настоящее время ему можно было бы предоставить один, здесь в этом нет необходимости. Представьте, что более поздний рефакторинг добавляет третий конструктор PartlyTaken (Int -> Grid) , который определяет, что происходит при добавлении чего-либо в местоположение; это предотвращает вывод Eq , но не должно препятствовать записи isOpen предиката, точно так же, как isNothing это не нужно Eq . Подводя итог, всегда лучше избегать (==) случаев, когда то, чего вы действительно хотите, — это анализ конкретного случая.

2. Я не уверен, почему это было отклонено. Это не лучшее решение, но оно по-прежнему выполняет то, что функция в вопросе должна была выполнять достаточно простым способом…