2015-02-21 3 views
1

Я пытаюсь написать программу игры Haskell «номер угадать», используя Монады, но я stucked:
Я попробовал простое состояние монады:Монада кортежей (монада, штат)?

data SM a = SMN (S -> (a, S)) 
instance Monad SM where 
SMN c1 >>= fc2 = SMN (\s0 -> let (r, s1) = c1 s0 in 
           let SMN c2 = fc2 r in 
            c2 s1) 

И мне нужно для выполнения задач ввода-вывода на «IO стороне» кортежа (а, S), то есть, я пытался делать что-то вроде:

SMN c1 >>= fc2 = SMN (\s0 -> let (r, s1) = c1 s0 in 
           let SMN c2 = fc2 r in 
           let (r1, s2) = c2 s1 in 
            let r2 = r1 >>= (\_ -> r) in 
            (r2, s2)) 

Короче говоря, оператор привязки Я хотел бы определить так же, как в исходном состоянии монады , за исключением того, что мы связываем r1 и константную функцию, которая принимает аргумент в r (так что эти два действия скованы ее). Но ghc говорит мне, что a - жесткая переменная типа ... Что это значит? Я не могу использовать другой оператор привязки внутри одного оператора привязки?
Если да, то есть ли способ реализовать такой оператор связывания? Как?
Как я новичок в Haskell (я думаю, что, возможно, имел нотационную ошибку относительно функции

\_ -> r 

), любое мнение и ссылки приветствуются, спасибо заранее.
P.S. Я использовал разные обозначения для типа данных SM и конструктора типов SMN, чтобы их отличить.

+0

Код очень запутанный. Не могли бы вы объяснить, что именно вы пытаетесь сделать? Для меня это звучит так, как будто вы пытаетесь построить нечто вроде «StateT s IO a». Вы можете найти варианты этого в 'Control.Monad.Trans.State.Strict' и' Control.Monad.Trans.State.Lazy'. Но я не могу сказать точно, потому что я не понимаю ваш код. – dfeuer

+0

@dfeuer Я хотел бы разделить действие монады и запись состояния в двух частях кортежа: (monad, state), чтобы я мог вызвать fst и snd, когда это необходимо, чтобы отделить их и выполнить некоторые подходящие действия. Я не знаю, как объяснить это явно, возможно, после того, как я завершу код, я могу показать использование этой монады, и тогда будет ясно, что я пытаюсь построить здесь. – awllower

ответ

7

Тип (>>=) является:

Monad m => m a -> (a -> m b) -> m b 

Поскольку вы пишете экземпляр для SM, тип привязки в вашем экземпляре поэтому

SM a -> (a -> SM b) -> SM b 

Обратите внимание, что оба a и b полностью переменные неограниченного типа. Это означает, что любая реализация, которую вы даете , должна работать независимо от того, какие типы я хочу разместить там. В частности, я мог выбрать, скажем, Int для обоих a и b:

SM Int -> (Int -> SM Int) -> SM Int 

И теперь понятно, почему ваша реализация не хорошо: он будет пытаться лечить Int, как если бы это было монадическая действие и позвоните по телефону (>>=).

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

data SMT m a = SMT (S -> m (a, S)) 

и дать пример, как:

instance Monad m => Monad (SMT m) where -- ... 

нормального SM затем может быть восстановлен, если вы хотите, с помощью Identity монады как вложенная монада ,

+0

'S -> (m a, S)' не работает, он не дает возможности внутренней монаде влиять на состояние. Вам нужно 'S -> m (a, S)'. –

+0

@ ØrjanJohansen Я не хочу, чтобы внутренняя монада тоже влияла на состояние, но все же благодарна за это предложение. – awllower

+0

@ ØrjanJohansen Это, безусловно, другой выбор; и это более общее. Спасибо, что указали это. –

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