2013-06-04 2 views
1

Мне нужно обернуть голову вокруг государственной монады в haskell, и у меня есть некоторые проблемы с этим. Задача состоит в реализации функции countConcat, которая объединяет строку с государственной монадой и функцией extractCC, которая получает результат этой функции.String concatenation with haskell state monad

Так extractCC ((return 0) >>= countConcat "a" >>= countConcat "b" >>= countConcat "c") уступит (3, «ABC»)

Насколько я понимаю countConcat бы вид функции манипулятора и extractCC должна содержать какую-то runState, верно?

Любые подсказки или источники, которые меня достают в правильном направлении, высоко ценятся. (I've был через вики и раздел learnyouahaskell, но все еще чувствовал себя довольно глупо с этим)

+3

Попробуйте написать без использования государства первого, то есть как функция 'String -> (Int, String) -> (Int, String) '. Затем снова посмотрите на объяснение состояния, чтобы увидеть, как эта функция отображается в монаде. Также начальным состоянием будет '(0," ")' (в первом 'return'). –

+0

Спасибо за ввод, я уже пробовал моделировать функцию без состояния, что было довольно легко. Моя проблема более подходит для подписи countConcat и реализации оператора bin для работы с цепочкой состояний. – floAr

ответ

5

Попробуйте это первый

concat' :: String -> State (Int,String)() 
concat' s = do 
    (c,st) <- get 
    put (c+1, st ++ s) 

Вы можете запустить на

> runState (concat' "A" >> concat' "B" >> concat' "C") (0,"") 
((),(3,"ABC")) 

Я думаю, если вы понимаете государственную монаду, вы можете изменить приведенный выше пример для своих нужд.

4

Благодаря Сатвику я смог решить проблему. Вот мое окончательное решение:

newtype State s a = State {runState :: s -> (a,s)} 

instance Monad (State s) where 
    return x = State (\s -> (x,s)) 
    (State h) >>= f = State (\s -> let (a, newState) = h s 
             (State g)  = f a 
            in g newState) 

         -- Save new state 
countConcat :: String -> Int -> State String Int 
countConcat s i =do 
    st <- get -- get current string 
    put ((st ++ s)) -- put conc. string 
    return (i+1) -- return new counter 


extractCC f =(runState f ("")) --run the function, staring with an empty string 


-- Helper from the wiki 
put newState = State $ \_ -> ((), newState) 
get = State $ \st -> (st, st) 

-- extractCC ((return 0) >>= countConcat "a" >>= countConcat "b" >>= countConcat "c") 
-- (3,"abc") 
0

Если вы используете first комбинатора из Control.Arrow, то:

countConcat :: String -> State (String,Int)() 
countConcat s = modify ((<> s) *** (+1)) 
+0

Это было очень чуждо мне, поэтому я много читал о типе Arrow в Haskell. Я думаю, что сейчас понимаю ***, но я не могу запустить его из-за <>, мне нужен специальный импорт здесь? – floAr