2016-10-24 1 views
1

Я хочу изменить свое состояние с функцией, которая зависит от старого состояния, но также вводит некоторую случайность. Моя функция f выглядит следующим образом:purescript-halogen: изменить состояние с помощью эффективных вычислений

f :: State -> Eff (random :: RANDOM) State 

Я думаю, мое состояние должно быть чистым, и я не имел ни малейшего представления о том, как избавиться от Eff, кроме использования unsafePerformEff, так что я сделал это:

eval :: Query ~> H.ComponentDSL State Query g 
eval (Tick next) = do 
    H.modify (unsafePerformEff <<< f) 
    pure next 

Это работает, но должен быть другой, более безопасный путь. Я уже добавил случайный эффект к моей основной функции:

main :: Eff (H.HalogenEffects (random :: RANDOM)) Unit 

Но как eval выглядеть? Может быть, modify здесь не работает, и есть другой способ обновить состояние?

Purescript Halogen, side effect (random number) не работает для меня, так как f зависит от старого состояния.

+0

Хорошо, я только что нашел Halogen 'get' и' set', но я все еще получаю ошибки типа. – stholzm

ответ

1

сам modify не позволяет выполнять effectful обновления, но да, вы можете использовать get и затем modify (или set) потом сделать это. Адаптировано из другого примера со случайным:

module Main where 

import Prelude 
import Control.Monad.Aff (Aff) 
import Control.Monad.Eff (Eff) 
import Control.Monad.Eff.Random (randomInt, RANDOM) 
import Halogen as H 
import Halogen.HTML.Events.Indexed as HE 
import Halogen.HTML.Indexed as HH 
import Halogen.Util (runHalogenAff, awaitBody) 

type State = { n :: Int } 

initialState :: State 
initialState = { n: 3 } 

data Query a = NewRandom a 

ui :: forall eff. H.Component { n :: Int } Query (Aff (random :: RANDOM | eff)) 
ui = 
    H.component { render, eval } 
    where 
    render :: State -> H.ComponentHTML Query 
    render state = 
     HH.button 
      [ HE.onClick $ HE.input_ NewRandom ] 
      [ HH.text $ show state.n ] 


    eval :: Query ~> H.ComponentDSL State Query (Aff (random :: RANDOM | eff)) 
    eval (NewRandom next) = do 
     state <- H.get 
     nextState <- H.fromEff (nextRandom state) 
     H.set nextState 
     pure next 

    nextRandom :: State -> Eff (random :: RANDOM | eff) State 
    nextRandom { n } = do 
     nextN <- randomInt (n + 1) (n + 10) 
     pure { n: nextN } 

main :: forall eff. Eff (H.HalogenEffects (random :: RANDOM | eff)) Unit 
main = 
    runHalogenAff do 
    body <- awaitBody 
    H.runUI ui initialState body 

Что может быть приводит к ошибке типа такой тип подписи, хотя:

f :: State -> Eff (random :: RANDOM) State 

Эффект ряд закрыт, то есть он не будет унифицировать с любым другим вы, вероятно, захотите это вместо этого:

f :: forall eff. State -> Eff (random :: RANDOM | eff) State 
+0

Я использовал закрытый ряд эффектов, потому что я знаю, что мои вычисления включают только случайность, и я хотел запретить любые другие эффекты. Но, видимо, это означает, что я не могу включить замкнутую строку в «открытый» ряд эффектов? Мне также потребовалось явно аннотировать '(Aff (random :: RANDOM | eff))' вместо просто 'g'. Спасибо, это заставило его скомпилировать! – stholzm

+1

Правильно - если вы использовали закрытую строку, вы застряли в ней для всей программы, поэтому она очень полезна только на верхнем уровне. Использование открытой строки позволяет только аннотированному выражению использовать эффекты, которые вы указываете в типе, но при открытии позволяет позднее объединиться с другими эффектными выражениями, добавив больше эффектов. И yep, 'g' определяет, какой тип должен использоваться для обработки« некомпонентных эффектов »в Halogen, поэтому, когда он не указан, он не допускает каких-либо эффектных операций. –

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