2015-03-14 2 views
1

Я хотел бы отслеживать «текущее» значение в последовательности неизменяемых значений. Каков наилучший способ сделать это в Haskell без введения новой ссылки для каждого нового значения? Вот пример:Переменные ссылки на неизменные данные в Haskell

data Person = Person {name, level, topic :: String } 
    deriving(Show) 

dierk :: Person 
dierk = Person "Dierk" "confident" "Java" 

works :: Person -> String 
works person = name person ++ " is " ++ level person ++ " in " ++ topic person 


main _ = do 
    putStrLn $ works dierk 
    -- do more with "current" topic 
    putStrLn $ works dierk {level= "proficient", topic="Groovy"} 
    -- do more with "current" topic 
    putStrLn $ works dierk {level= "dabbling", topic="Haskell"} 
    -- do more with "current" topic 
+0

От этого зависит. Мутабельность может быть получена через монаду «Государственная личность». Если вам также нужно сделать IO поверх этого, тогда вам, вероятно, понадобится «StateT Person IO». – chi

+0

Государственная монада не сокращает ее, так как вы только получаете правопреемство государства (новые состояния с каждым изменением), но не ссылаются на «текущее» состояние. – Dierk

+3

Мне очень непонятно, что вы пытаетесь выразить в этом фрагменте псевдокода. – dfeuer

ответ

3

Я не уверен, о том, что вопрос на самом деле просит. Опубликованный пример можно переписать для использования монады StateT Person IO следующим образом.

import Control.Monad.State 

data Person = Person {name, level, topic :: String } 
    deriving Show 

dierk :: Person 
dierk = Person "Dierk" "confident" "Java" 

works :: Person -> String 
works person = name person ++ " is " ++ level person ++ " in " ++ topic person 

main :: IO() 
main = flip evalStateT dierk $ do 
    -- use the current topic 
    lift . putStrLn . works =<< get 
    -- change the current topic 
    modify (\t -> t{level= "proficient", topic="Groovy"}) 
    lift . putStrLn . works =<< get 
    -- change the current topic 
    modify (\t -> t{level= "dabbling", topic="Haskell"}) 
    lift . putStrLn . works =<< get 

{- Output: 
Dierk is confident in Java 
Dierk is proficient in Groovy 
Dierk is dabbling in Haskell 
-} 

Если вместо реальной ссылочного типа разыскивается, можно было бы использовать IORef Person или STRef если в ST монады. Но в таком случае вы должны работать внутри монады, допускающей эти ссылочные типы. Для сравнения: StateT Person m работает в любой монаде m.

+0

Спасибо, это, безусловно, решение для моего вопроса. – Dierk

0

Просто чтобы обернуть и дать подсказки другим новичкам Haskell, таким как я, - вот решение, с которым я наконец решил. Это не псевдокод :-), а Frege (Haskell для JVM), который имеет некоторые незначительные отличительные отличия.

module Person where 

import frege.control.monad.State 

data Person = Person {name, level, topic :: String } 

derive Show Person 

dierk = Person "Dierk" "confident" "Java" 

works :: Person -> String 
works person = person.name ++ " is " ++ person.level ++ " in " ++ person.topic 

printCurrentPerson :: StateT Person IO() 
printCurrentPerson = do 
    person <- StateT.get   -- independent of any particular person reference 
    StateT.lift $ println $ works person 

updateCurrentPerson :: Monad m => String -> String -> StateT Person m() 
updateCurrentPerson level topic = do 
    StateT.modify (\person -> Person.{level= level, topic=topic} person) 

usingMutableRefsToImmutableState :: Person -> IO ((),Person) 
usingMutableRefsToImmutableState start = 
    flip StateT.run start $ do 
     printCurrentPerson 
     updateCurrentPerson "proficient" "Groovy" 
     printCurrentPerson 
     StateT.lift $ println "-- user input could influence which selection is 'current' " 
     updateCurrentPerson "dabbling" "Haskell" 
     printCurrentPerson 

main = do -- using the StateT transformer to work in combination with any monad (here: IO) 
    (_, lastPerson) <- usingMutableRefsToImmutableState dierk 
    println "-- a second round with relaying the last person" 
    _ <- usingMutableRefsToImmutableState lastPerson 
    return() 

{- output 
    Dierk is confident in Java 
    Dierk is proficient in Groovy 
    -- user input could influence which selection is 'current' 
    Dierk is dabbling in Haskell 
    -- a second round with relaying the last person 
    Dierk is dabbling in Haskell 
    Dierk is proficient in Groovy 
    -- user input could influence which selection is 'current' 
    Dierk is dabbling in Haskell 
-} 

Спасибо всем.

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