tag:blogger.com,1999:blog-1777990983847811806.post1097061300079286878..comments2024-03-16T16:29:29.582-07:00Comments on Haskell for all: Program imperatively using Haskell lensesGabriella Gonzalezhttp://www.blogger.com/profile/01917800488530923694noreply@blogger.comBlogger45125tag:blogger.com,1999:blog-1777990983847811806.post-70843830443036977282017-02-05T23:15:27.661-08:002017-02-05T23:15:27.661-08:00Gabriel, thanks for this fantastic write up!
Ins...Gabriel, thanks for this fantastic write up! <br /><br />Inspired from your blog post I have ported all your Haskell code into PureScript to get a better understanding of using states and lenses in PureScript: https://github.com/sectore/program-imperatively-using-purescript<br /><br />It is just fun :)<br /><br />-Jenssectorehttps://www.blogger.com/profile/13500061581551190654noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-61122134328837331822016-06-03T05:10:04.959-07:002016-06-03T05:10:04.959-07:00This is very cool, your blog is always very easy t...This is very cool, your blog is always very easy to read.<br /><br />Now I wonder, all your "actions" are of Type Game -> Game, effectively meaning that an action like (fireBreath) is issued by the game world, and not the Boss.<br /><br />Now I'm curious if it's possible like you would in C++ or similar, to assign specific actions to your units, This means that a Unit has control of itself, and you could effectively isolate off illogical actions, like the players using fireBreath, (or in more complicated situations, like requiring a spell book, before you can cast a spell from it!)<br /><br />An interesting situation is that in a multiplayer game someone might try to manipulate network packets, to modify what kind of attack the player is issuing, if all attacks are part of the world, its theoretical that a player (without runtime checks) could issue a spell he does not have. (For example, spells would have a global Enum value, instead of the boss and player having their own Enums)Danielhttps://www.blogger.com/profile/03579451127151648932noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-15516249628452192892015-09-09T07:15:38.389-07:002015-09-09T07:15:38.389-07:00My understanding is that you can use lenses for th...My understanding is that you can use lenses for this but you pay an efficiency price when they refer to mutable references. You can use them, but you usually end up having to touch the mutable reference twice for every lens-based operation.Gabriella Gonzalezhttps://www.blogger.com/profile/01917800488530923694noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-23048007992751451902015-09-08T04:42:36.662-07:002015-09-08T04:42:36.662-07:00How can this be used with https://github.com/ekmet...How can this be used with https://github.com/ekmett/structs ?Janus Troelsenhttps://www.blogger.com/profile/16955941075243047389noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-66611152800453690732015-08-19T20:42:50.524-07:002015-08-19T20:42:50.524-07:00To expand on this, the subexpression (around targe...To expand on this, the subexpression (around target 1.0) is an outlaw traversal, but larger subexpression ((around target 1.0).health) is a valid traversal, so in that sense there is nothing wrong with your code. Because the target and health are disjoint lenses, the danger of around has been diffused, and this is almost always how the filter function ends up being used in practice.<br /><br />There is a lawful way to write this sort of program (i.e. so that all lensy subexpressions are law abiding) but it is so awkward t do that I cannot realistically recommend it. What I personally might do instead is rewrite around so the the code ends up instead as (around target 1.0 health) and while this isn't technically any safer, at least there is a place in the precondition for the around function for me to comment that the two lens arguments must be disjoint lenses.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-3044022778879298672014-11-07T09:06:07.021-08:002014-11-07T09:06:07.021-08:00Using existing operators, you would have to do thi...Using existing operators, you would have to do this:<br /><br /> d <- use (player.damage)<br /> boss.health .= d<br /><br />However, there is nothing preventing you from defining your own operator for this purpose:<br /><br /> l1 -== l2 = do<br /> d <- use l1<br /> l1 .= l2<br /><br />Gabriella Gonzalezhttps://www.blogger.com/profile/01917800488530923694noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-45005769938327792062014-11-07T07:14:09.393-08:002014-11-07T07:14:09.393-08:00Great article. But is there any way to do somethin...Great article. But is there any way to do something like this?<br /><br />strike :: StateT Game IO ()<br />strike = do<br /> lift $ putStrLn "*shink*"<br /> boss.health -= player.damage<br /><br />assuming we have defined <br /><br /> data Player = Player {_health, _damage :: Int }<br /><br />and included it in the Game record?Anonymoushttps://www.blogger.com/profile/14243542383939862822noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-79206699776734078082014-05-02T16:39:17.682-07:002014-05-02T16:39:17.682-07:00Sorry, I meant to say that I had begun writing the...Sorry, I meant to say that I had begun writing the tutorial but it is not complete yet.Gabriella Gonzalezhttps://www.blogger.com/profile/01917800488530923694noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-73132029760059266482014-04-20T18:17:26.438-07:002014-04-20T18:17:26.438-07:00Could you please point me to the tutorial you have...Could you please point me to the tutorial you have in mind? Anonymoushttps://www.blogger.com/profile/07172601379596292053noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-21971440140279346462014-02-21T07:13:05.067-08:002014-02-21T07:13:05.067-08:00I do have a lens tutorial for the pure lend operat...I do have a lens tutorial for the pure lend operations and I will throw in uniplate/biplate.Gabriella Gonzalezhttps://www.blogger.com/profile/01917800488530923694noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-64101559609086786132014-02-21T07:11:04.597-08:002014-02-21T07:11:04.597-08:00Gabriel, thanks a lot for this fantastic tutorial....Gabriel, thanks a lot for this fantastic tutorial. Could you please also write another one showing how to use uniplate/biplate generics using the lens package?Anonymoushttps://www.blogger.com/profile/07172601379596292053noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-77229214529024052512014-02-05T07:22:20.528-08:002014-02-05T07:22:20.528-08:00Thank you so much!Thank you so much!Anonymoushttps://www.blogger.com/profile/14374344835171319082noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-56316165341881984842014-02-04T21:22:16.773-08:002014-02-04T21:22:16.773-08:00`StateT` already implements the `MonadTrans` type ...`StateT` already implements the `MonadTrans` type class. The `transformers` library that we get `StateT` from also provides this `MonadTrans` instance for `StateT`. You can find the code in this module:<br /><br />http://hackage.haskell.org/package/transformers-0.3.0.0/docs/src/Control-Monad-Trans-State-Lazy.html<br /><br />That module is in turn re-exported by `Control.Monad.Trans.State`, which is why that `MonadTrans` instance was in scope.Gabriella Gonzalezhttps://www.blogger.com/profile/01917800488530923694noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-61562328151193636322014-02-04T14:51:43.994-08:002014-02-04T14:51:43.994-08:00First off, a very great article. I had a lot to le...First off, a very great article. I had a lot to learn about this. I am curious however, that how can you use the lift function before defining what it is? i.e. you have't declared (StateT Game) an instance of class MonadTrans t. It is only when you define it as an instance, then you provide the implementation for the lift method. Is this somehow done automatically? Did I miss something?Anonymoushttps://www.blogger.com/profile/14374344835171319082noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-25305188179920993122013-10-23T20:19:54.806-07:002013-10-23T20:19:54.806-07:00Thanks for your reply! I'll check out the link...Thanks for your reply! I'll check out the links.Anonymoushttps://www.blogger.com/profile/00262558134372499553noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-6239262968527426982013-10-23T16:06:20.288-07:002013-10-23T16:06:20.288-07:00Yes. I totally agree that it makes working with ne...Yes. I totally agree that it makes working with nested record data types so much easier.<br /><br />I'm definitely writing up a book once I finish my thesis (really soon).<br /><br />For additional tricks and example, consult the lens wiki on the Github repository here:<br /><br />https://github.com/ekmett/lens/wiki/_pages<br /><br />A good start is this page:<br /><br />https://github.com/ekmett/lens/wiki/Examples<br /><br />... and also check out the examples directory:<br /><br />https://github.com/ekmett/lens/tree/master/examplesGabriella Gonzalezhttps://www.blogger.com/profile/01917800488530923694noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-86188481768326084432013-10-22T18:26:42.267-07:002013-10-22T18:26:42.267-07:00This is a really fantastic tutorial. Now I can sta...This is a really fantastic tutorial. Now I can start using lenses right away without having to have spent hours learning the theory behind them. It's amazing that these imperative-like constructs have been built using purely functional concepts, such as functors. Though it looks like there is some serious Haskell wizardry going on under the covers. If this library catches on, it could deeply impact how we write Haskell, especially when we deal with nested record data types (and perhaps in many other ways, too; I'm still very new to all this).<br />Thank you so much. I really hope you write a book.<br />If you know of similar tutorials that show how to use other combinators, let me know. I'd also like to know if there are other neat tricks in addition to "traversed" and "zoom".Anonymoushttps://www.blogger.com/profile/00262558134372499553noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-58754255944497754672013-07-02T08:46:46.827-07:002013-07-02T08:46:46.827-07:00Thank you!
I haven't forgotten about the book...Thank you!<br /><br />I haven't forgotten about the book at all. A lot of these blog posts are practice for the book, except the book will be more detailed.Gabriella Gonzalezhttps://www.blogger.com/profile/01917800488530923694noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-64700692742920808872013-07-02T04:19:08.363-07:002013-07-02T04:19:08.363-07:00Great post!
Don't forget your book, your write...Great post!<br />Don't forget your book, your write looks very nice to read!!!!Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-78084935971241090892013-06-17T12:55:53.290-07:002013-06-17T12:55:53.290-07:00You're welcome! :)You're welcome! :)Gabriella Gonzalezhttps://www.blogger.com/profile/01917800488530923694noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-60873802138984117042013-06-17T12:51:46.650-07:002013-06-17T12:51:46.650-07:00Just another "Thank you for this article"...Just another "Thank you for this article" from me ... made me start using lenses :)Florianhttps://www.blogger.com/profile/09818883353574599794noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-84945067902410516332013-06-08T19:02:20.664-07:002013-06-08T19:02:20.664-07:00Thank you! I really appreciate that!
Let me advi...Thank you! I really appreciate that!<br /><br />Let me advise you of one thing: don't wait until you are good enough to start writing tutorials, too. This is the mistake that every Haskell programmer makes and the reason why there are no good Haskell tutorials! :)<br /><br />You should make a habit of writing from the beginning, because if you don't exercise that skill early on you won't be able to write well when you become expert. The whole reason I got better at tutorials is that I practiced doing so even while I was a beginner. I would just submit everything I wrote to /r/haskell and they would tear it apart week after week. At first I would get defensive and be a bit ashamed, but after doing this over and over again and learning from their criticisms my writing style and skills improved.<br /><br />Also, writing will help improve your own understanding of the language. Nothing teaches yourself better than teaching others.Gabriella Gonzalezhttps://www.blogger.com/profile/01917800488530923694noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-2802584267194514202013-06-08T18:42:10.347-07:002013-06-08T18:42:10.347-07:00Gabriel, Thanks for this tutorial. I started learn...Gabriel, Thanks for this tutorial. I started learning Haskell last year and after about 80 project Euler problems, I thought that Haskell was the greatest language ever. Then I decided to start writing a nosql db in haskell and my enthusiasm was diminishing rapidly until I saw this tutorial which clearly explained lens. <br />Most haskell tutorials I have seen use examples that take as much effort to understand as the concepts they are trying to teach. Your example did not get in the way of the concepts that you were teaching making it one of the best I have seen in the Haskell world. I wish that others would copy you. I intend to if I get good enough to write something usefull.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-62983168084702512632013-06-07T18:51:31.585-07:002013-06-07T18:51:31.585-07:00Cheers, (.=) makes sense, I'll do that. :)Cheers, (.=) makes sense, I'll do that. :)Anonymoushttps://www.blogger.com/profile/05000506241732628090noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-28003949745128225612013-06-07T07:49:54.558-07:002013-06-07T07:49:54.558-07:00What you described is the .= operator:
xLens ...What you described is the .= operator:<br /><br /> xLens .= x<br /><br />... which is equivalent to:<br /><br /> xLens %= (\_ -> x)<br /><br />The `first` function you described exists in the Prelude and is known as `const`:<br /><br /> const :: a -> b -> a<br /> const a b = aGabriella Gonzalezhttps://www.blogger.com/profile/01917800488530923694noreply@blogger.com