tag:blogger.com,1999:blog-22587889.post7594385420867612238..comments2024-02-11T13:21:47.930+05:30Comments on Ruminations of a Programmer: Functional Patterns in Domain Modeling - Composing a domain workflow with statically checked invariantsAnonymoushttp://www.blogger.com/profile/01613713587074301135noreply@blogger.comBlogger14125tag:blogger.com,1999:blog-22587889.post-35885019010526025272017-07-20T11:50:33.500+05:302017-07-20T11:50:33.500+05:30Learning is a process. Great site.Learning is a process. Great site.durphttp://urbanplanning.uonbi.ac.kenoreply@blogger.comtag:blogger.com,1999:blog-22587889.post-89776828586307454572017-06-21T11:53:42.377+05:302017-06-21T11:53:42.377+05:30great site, great articlegreat site, great articlephelisiahttp://arts-design.uonbi.ac.kenoreply@blogger.comtag:blogger.com,1999:blog-22587889.post-57751495109810519402015-10-23T16:07:44.381+05:302015-10-23T16:07:44.381+05:30This comment has been removed by the author.Monahttps://www.blogger.com/profile/14162518810786555495noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-67632655580001257312015-09-26T19:27:50.219+05:302015-09-26T19:27:50.219+05:30@Unknown -
You can always use monads natively to ...@Unknown -<br /><br />You can always use monads natively to model this use case. Kleisli offers a higher level of abstraction and hence makes your code much more readable. Compare the version of process() function with the one written using kleisli - it reads better from the domain modeling point of view. The sequencing is more explicit as a DSL. But the more important point is that the andThen combinator of Kleisli uses the same algebra of the monad. See it's implementation at https://github.com/scalaz/scalaz/blob/series/7.2.x/core/src/main/scala/scalaz/Kleisli.scala#L15 which uses the bind. It's all about programming at the right level of abstraction. Once you have the functions returning a Kleisli you have at your disposal all the combinators that a Kleisli arrow offers. You suddenly have more higher order power to glue your components.Anonymoushttps://www.blogger.com/profile/01613713587074301135noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-75001732101109110992015-09-26T01:00:05.806+05:302015-09-26T01:00:05.806+05:30Great post! I'm still trying to grasp the adva...Great post! I'm still trying to grasp the advantage of using Kleisli arrows over simple monad binding to compose functions. I rewrote your <a href="https://github.com/debasishg/scala-snippets/blob/master/src/main/scala/aggregate.scala" rel="nofollow">example</a> using flatMaps: <a href="https://gist.github.com/kciesielski/b882f75528fac69b2635" rel="nofollow">HERE</a>. <br /><br />Could you give me a hint what do we lose by switching to the second option in this case?Anonymoushttps://www.blogger.com/profile/15306037471407772877noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-22608444691034229402015-03-01T00:42:45.128+05:302015-03-01T00:42:45.128+05:30l.copy[Approved](...) would probably workl.copy[Approved](...) would probably workEECOLORhttps://www.blogger.com/profile/14248827614136876880noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-30730842812076129252015-02-28T23:13:43.914+05:302015-02-28T23:13:43.914+05:30Hi Ivano -
I don't think there's any opti...Hi Ivano -<br /><br />I don't think there's any option other than using the map(identity[..]). This is because the phantom types are there only for this purpose and do not take any part in logic. So we need to force a coercion on to them.<br /><br />Regarding lenses, yes, we can of course replace the copy with lens. In fact with complex domain models that's the recommended approach. Here it's a simple example and the point I wanted to demonstrate is something different. Hence I used the copy for illustration purposes.<br /><br />Thanks.Anonymoushttps://www.blogger.com/profile/01613713587074301135noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-60050912560288860072015-02-28T20:20:39.775+05:302015-02-28T20:20:39.775+05:30Good article as ever.
I don't really like the ...Good article as ever.<br />I don't really like the way you have to map with identity to force the correct phantom type.<br />Is there a neater solution to that?<br />And could the code be made better still, using lenses?<br /><br />Thank you<br />Ivanopagoda_5bhttps://www.blogger.com/profile/16499815949180321471noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-14255594447343333552015-02-23T11:37:24.140+05:302015-02-23T11:37:24.140+05:30Excellent article.
This only appears to work for ...Excellent article.<br /><br />This only appears to work for simple linear workflows.<br /><br />How do you model such things as loops, optional stages, or joins/meets? I can't help thinking extending this might end up needing dependent types?Andrae Muyshttps://www.blogger.com/profile/04967415260912980895noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-33292205404864546572015-02-13T00:34:49.714+05:302015-02-13T00:34:49.714+05:30Nice article DebashishNice article DebashishSatishhttps://www.blogger.com/profile/07728575857244234737noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-80285018640316589202015-02-12T19:29:43.366+05:302015-02-12T19:29:43.366+05:30Thanks Stephan .. Glad that you liked it.Thanks Stephan .. Glad that you liked it.Anonymoushttps://www.blogger.com/profile/01613713587074301135noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-87414671034464946582015-02-12T14:28:56.596+05:302015-02-12T14:28:56.596+05:30Very nice article, learned something, and the neat...Very nice article, learned something, and the neat little usage of identity to change types.Stephan.Schmidthttps://www.blogger.com/profile/03845125686370893937noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-91911650731104796922015-02-12T11:40:24.509+05:302015-02-12T11:40:24.509+05:30When you have functions with return type LoanAppli...When you have functions with return type LoanApplied => LoanApproved, you cannot handle effects. e.g. the approval process may fail and this needs to be indicated in the return type. Also the sequence needs to be broken if one of the steps fail. Hence the return type can be LoanApplied => Option[LoanApproved] where Option indicates the possibility that the approval may fail.<br /><br />And Kleisli is precisely a generalization of this - a Kleisli models an effectful function application. Kleisli[M, A, B] models A => M[B] where M is the effect (Option in this example).<br /><br />Hence Kleisli is a better option since we can have effects along with the sequencing.Anonymoushttps://www.blogger.com/profile/01613713587074301135noreply@blogger.comtag:blogger.com,1999:blog-22587889.post-51627392818871110672015-02-12T03:37:21.270+05:302015-02-12T03:37:21.270+05:30I like your use of shadow types.
I must be missin...I like your use of shadow types.<br /><br />I must be missing something (which might be hidden in the terminology you are using). The following seems to work just fine:<br /><br />val approve: LoanApplied => LoanApproved =<br /> _.copy(<br /> loanNo = Some(scala.util.Random.nextString(10)),<br /> actualRepaymentYears = Some(15),<br /> startDate = Some(today))<br /><br />val enrich: LoanApproved => LoanEnriched = { l =><br /> val x = for {<br /> y <- l.actualRepaymentYears<br /> s <- l.startDate<br /> } yield (y, s)<br /><br /> l.copy(emi = x.map { case (y, s) => calculateEMI(y, s) })<br />}<br /><br />val l = applyLoan("john", "house building", 10)<br />val op = approve andThen enrichEECOLORhttps://www.blogger.com/profile/14248827614136876880noreply@blogger.com