Я все еще делаю упражнение из книги, и одно упражнение говорит, что я должен создать функцию: value :: Hand -> Int
, которая возвращает значение руки.
Мой код пока выглядит так:
data Hand = PairOf Rank | ThreeOf1 Rank | ThreeOf2 Suit
value: Hand -> Int
otherwise = 0
--
Теперь у меня другая проблема, потому что я не знаю, как описать «Ничто». Здесь ничего не описано как возможная комбинация рук, в которой не встречаются Pair, ThreeOf1 и ThreeOf2. В противном случае = 0 будет работать или это не имеет особого смысла?
Еще раз спасибо за предложения, я их исправил! Также заранее спасибо за разъяснения и помощь.
Вероятно, использование Nothing
в качестве одного из ваших конструкторов — плохая идея, так как Nothing
уже используется библиотекой Haskell в качестве конструктора Maybe
.
У вас могут быть предложения сопоставления с образцом в вашей функции value
, например: value (Flush s0 s1 s2) = 3
«... или их ранги равны, и решают масти». - Но Haskell по умолчанию использует лексикографический порядок, так что это именно то, что вы получите, просто используя deriving (Show, Eq, Ord)
Некоторые из ваших конструкторов Hand
слишком общие. PairOf Seven Seven
имеет смысл, конечно, но как насчет PairOf Seven Eight
. PairOf
сама по себе уже подразумевает две карты равного достоинства; вам нужно только указать, какой это ранг. PairOf Rank
достаточно. То же самое относится и к ThreeOf
и Flush
(флеш — это уже все карты одной масти; просто назовите ту масть, которая является общей для всех карт, а не идентичную масть каждой карты в отдельности).
Спасибо всем! Я понял это, и теперь это работает, но как я могу сделать это с помощью Nothing? не могли бы вы подсказать и объяснить?
Где вы дали указание использовать такой тип данных Hand
? На мой взгляд, более сложным (и интересным) является просмотр группы карт и вычисление того, есть ли у вас пара, тройка, флеш и т. д. Ваша функция value
начинается с типа, который фактически уже содержит информацию о какое там значение (поэтому вы можете игнорировать все фактическое содержимое конструкторов Hand
; значение уже определяется тем, какой конструктор был там). Но это еще не позволило бы вам определить ценность произвольного набора из 5 карт.
то есть я ожидал, что value :: Hand -> Int
будет сочетаться с чем-то вроде type Hand = [Card]
, а не data Hand = PairOf ... | ...
. Но, возможно, они подготавливают вас к другой функции, которая позже перейдет от [Card]
к Hand
.
otherwise
здесь не работает. Вам нужен неопровержимый шаблон, который будет соответствовать чему угодно, и, кроме того, поскольку вам все равно, что совпадет, вам нужен именно шаблон _
:
value :: Hand -> Int
value (PairOf r1) = 1
value (ThreeOf r1) = 2
value (Flush s1) = 3
value _ = 0
Поскольку вам все равно, какую пару вы получите и т. д., вы также можете использовать _
в других случаях:
value :: Hand -> Int
value (PairOf _) = 1
value (ThreeOf _) = 2
value (Flush _) = 3
value _ = 0
Если вы хотите сопоставить Nothing
(или любое другое имя, которое вы придумаете, которое не конфликтует с конструктором Maybe
), это просто
value Nothing = 0
Одна из проблем, с которой вы можете столкнуться, заключается в том, что Ничто не существует.
Вот полный тип рук для холдема:
data HandRank
= HighCard Rank Rank Rank Rank Rank
| OnePair Rank Rank Rank Rank
| TwoPair Rank Rank Rank
| ThreeOfAKind Rank Rank Rank
| Straight Rank
| Flush Rank Rank Rank Rank Rank
| FullHouse Rank Rank
| FourOfAKind Rank Rank
| StraightFlush Rank
deriving (Eq, Ord, Show, Generic)
Дополнительные ранги в типе данных предназначены для различения рук, поэтому пара тузов с кикером короля и дамы бьет пару тузов с кикером короля и валета. Но в остальном это то же самое, что и ваша установка.
Как только у вас есть полное преобразование из набора карт в ценность руки, нет ничего. То, о чем вы, возможно, подумали как о чем-то, это линия HighHand в типе суммы. Если ваш контекст подходит для возможных рук, то я бы добавил NoValue к типу суммы рук, что лучше, чем вывод Maybe Hand
.
Использование подстановочных знаков otherwise _
или value _
может привести к ошибке, потому что вы можете забыть о кодировании, скажем, фулл-хауса, и ваша существующая функция будет работать. Если вы забудете закодировать один из типов суммы и у вас нет шаблона match-any, компилятор будет жаловаться. Предоставление компилятору всех ветвей типа суммы также является горячей областью разработки GHC, и это будет быстро.
«или их ранги равны, а масти решают» Это не то, что на самом деле делает ваша функция. "2 карты одного ранга" Тогда почему вы дважды включаете ранг? Вы можете включить ранг и две масти, если хотите, чтобы значение
Hand
представляло уникальную руку. То же самое и во всех остальных случаях. «Я точно не знаю, как создать функцию значения». Используйте сопоставление с образцом. Любой учебник или учебник по Haskell должен объяснять это на одной из первых страниц.