2014-10-13 10 views
3

В качестве задания мне нужно работать с монадами в Haskell и создавать игровую игру, в которой есть одно простое правило: бросить 6 монет, подсчитать головы, бросить кубик и если его результат равен или больше, чем количество голов, которые вы считаете побежденным, иначе вы проиграете. Я получил следующее «рамки», ограничивающую Игорный Монадой:Haskell: Работа с классами монады

data Coin = H | T 
    deriving (Bounded, Eq, Enum, Ord, Show) 

data Dice = D1 | D2 | D3 | D4 | D5 | D6 
    deriving (Bounded, Eq, Enum, Ord, Show) 

data Outcome = Win | Lose 
    deriving (Eq, Ord, Show) 

class Monad m => MonadGamble m where 
    toss :: m Coin 
    roll :: m Dice 

game :: MonadGamble m => m Outcome 
game = undefined 

Однако я еще новичок в монад, и я понятия не имею, как работать с ними. Например: определение игры должно реализовать игру, описанную выше, но как мне работать с этой Монархией азартных игр, чтобы, например, выполнить один или несколько бросков (-ов)/ролл (ы) и получить результирующие значения, Я могу использовать/работать с ними?

Также из моего понимания у Монады всегда есть две функции по умолчанию: return and (>> =), но я не вижу, как это применимо к монаде MonadGable?

Если кто-нибудь может мне помочь, это очень ценится!

С уважением, Skyfe.

+0

Вы можете написать всю логику игры, не имея реализацию 'MonadGamble', а затем вы можете написать« экземпляр MonadGamble some_existing_monad, где ... », чтобы получить фактическое поведение, в котором оно выполняется. – bheklilr

+0

Просто, чтобы быть ясным: в Haskell «тип» представляет собой (примерно) набор значений. «Класс» (несколько менее грубо) представляет собой набор типов (а не набор значений). Таким образом, «MonadGamble» представляет собой набор типов, каждый из которых имеет операции '>> =' и 'return', а также операции' MonadGamble' 'toss' и' roll'. –

ответ

7

Во-первых, MonadGamble технически не монада здесь, а класс типов расширения монады так, что у него есть две вещи, связанные с ним: toss и roll, каждый означающий значение броске или булочку соответственно. В типе подписи game, m является монадой, и это пример MonadGamble, поэтому мы автоматически имеем доступ к нам toss и roll.

Здесь вы можете использовать обозначения Haskell. Я не буду вдаваться в излишние подробности, как я не хочу делать все задания, но вот как вы могли бы написать монаду, которая проверяет, если две монеты подбрасывает придумали один и тот же:

twoFlips :: MonadGamble m => m Bool 
twoFlips = do 
    coin1 <- toss 
    coin2 <- toss 
    return (coin1 == coin2) 

Вы также можете найти полезные replicateM функцию из Control.Monad, что позволяет повторить монадическое действие и возвращают результаты в списке:

import Control.Monad (replicateM) 

tenCoins :: MonadGamble m => m [Coin] 
tenCoins = replicateM 10 toss 
+0

Спасибо! Я полагал, что я должен использовать структуру Haskell, используя <-, хотя я не уверен, что он делает, кроме сохранения результирующих значений, которые будут использоваться конечной функцией, однако я не понимаю, как я должен фактически получать реальные значения (например) coin1 и coin2? Потому что это монад правильно, но как я могу получить реальную ценность, которая лежит внутри них? (например, f coin1 = H или T)? – user2999349

+0

Это именно то, что делает '' <-''. Он извлекает «реальное» значение, содержащееся в монаде, и присваивает ему имя (это то, что мы имеем в виду, когда говорим, что мы «связываем» монадическое значение). Нам разрешено делать это только в блоке do, потому что мы вынуждены затем обнулить значение в монаде в конце блока. –

3

Вы можете думать о MonadGamble как мин-языке, с четырьмя конструкций:

do 
    x <- a 
    b 

, который запускает программу a следуют программы b (где, в b, переменная x относится к результату a),

return x 

которая является простой программой, которая просто возвращает x,

toss 

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

roll 

, который представляет собой простую программу, которая катит матрицу один раз и возвращает результат (одна из шести граней D1 - D6).

Следует отметить, что конструкции Monad>>= и return также являются конструкциями языка MonadGamble; это то, что означает Monad m => в декларации MonadGamble.

Что вам нужно сделать, это написать программу, которая реализует описанную игру, используя четыре «конструкции», определенные выше. Поскольку вы новичок в монадах, вы, вероятно, захотите написать игру, просто используя эти четыре конструкции, подумайте, как вы могли бы упростить ее, написав свои собственные вспомогательные функции, а затем посмотрите на standard Monad library, чтобы узнать, какие имена он дает для ваших вспомогательных функций (Я сомневаюсь, что вам понадобится то, чего у него нет).

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

-- | Roll the die, then if the result is 1-3 flip the coin once, otherwise twice, 
-- returning a list of the results. 
roller = do 
    d <- roll 
    if d `elem` [ D1, D2, D3 ] 
     then do 
      c <- flip 
      return [ c ] 
     else do 
      c0 <- flip 
      c1 <- flip 
      return [ c0, c1 ] 

 Смежные вопросы

  • Нет связанных вопросов^_^