5

I'm trying to start using scalaz in my lift project. For that purpose I'm rewriting some code to meet the style. Consider a code for logging in a user:

  def login: CssSel = {
    var password = ""
    def submit() {
      if (doLogin) S.redirectTo("/index")
      else S.error("Wrong password")
    }
    "name=pwd"    #> SHtml.password(password, password = _) &
    "type=submit" #> SHtml.onSubmitUnit(submit)
  }

So, this should be rewritten using a state monad somehow. But I just don't get, how. Trying this:

val result = for {
    s       <- init[String]
    pass    <- SHtml.password(s, put(_))
    newPass <- init[String]
    res     <- "name=pwd"    #> pass &
               "type=submit" #> SHtml.onSubmit { _ =>
                 if (User.logIn("username", newPass)) S.redirectTo("/index")
                 else S.error("Wrong password")
               }
} yield (newPass, res)
result ! ""

UPD: Updated example, according to answers.

Any good tutorials/explanations on state monads in scalaz, showing how to use gets, put, etc?

George
  • 8,368
  • 12
  • 65
  • 106
  • Did you have a look at my earlier question/answer? http://stackoverflow.com/questions/7734756/scalaz-state-monad-examples – huynhjl Dec 13 '11 at 15:02
  • 2
    I’m not sure this is really practical. You can’t just use some state monad and magically get rid of all `var`s in your code. For this to work you must have some means of chaining the state changes which the callback methods of Lift’s `SHtml` do not support. (I think the whole concept of Lift is precisely that you use variables hidden in many closures.) I’d be happy to be proven wrong, though, and see a working example of this. – Debilski Dec 13 '11 at 15:10

2 Answers2

2

The best scalaz examples I have found so far are these: http://etorreborre.blogspot.com/2011/06/essence-of-iterator-pattern.html?m=1 http://etorreborre.blogspot.com/2011/12/pragmatic-io.html?m=1 And the follow ups. This example from scalaz examples :) https://github.com/scalaz/scalaz/blob/scalaz-seven/example/src/main/scala/scalaz/example/WordCount.scala

In the word count example it counts 3 values and the wordcount value is calculated through using state. I hope this helps.

AndreasScheinert
  • 1,918
  • 12
  • 18
2

Warning: I've never used the Scala state monad. However, I think I see the reason it behaves as you say it does.

onSubmit sees the old pass, not the one, I'm put'ting

Well, look at what you are doing:

... { pass =>
  ... SHtml.password(pass, _ => put(pass))
  ... User.logIn("username", pass)
}

Firstly, I don't think you are putting what you think you're putting. Try this instead:

... SHTML.password(pass, newPass => put(newPass))

Secondly, I don't think you are getting what you think you're getting. I have no clue how Scalaz state monad works, but it should be something like this:

... User.logIn("username", get())

I don't think that you use pass to refer to the changing state; pass is simply the value that is given to the state computation to begin with, which would explain why User.logIn("username", pass) is using the "old" oassword.

Also (though I don't know SHtml or what & does) I highly doubt this will actually work. It's hard to explain why I think this, but it has something to do with SHtml probably not being friendly with constructing state expressions inside of itself, as Debilski commented. SHtml.password seems to expect you to give it an arbitrarily side-effecting function; this design choice immediately makes it unfriendly to a functional approach for the thing you are attempting to do.

Dan Burton
  • 53,238
  • 27
  • 117
  • 198
  • 1
    This is an incomplete and possibly horrible answer. Those that actually know about Lift and scalaz: please vote/comment as appropriate to confirm/deny my conclusions. – Dan Burton Dec 13 '11 at 23:58