#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. Я не уверен, почему это было отклонено. Это не лучшее решение, но оно по-прежнему выполняет то, что функция в вопросе должна была выполнять достаточно простым способом…