transformers

207 views
Skip to first unread message

Jason Zaugg

unread,
Apr 21, 2012, 12:12:16 PM4/21/12
to sca...@googlegroups.com
I'm wondering whether we ought to manually specialize our transformers
(e.g. StateT, LensT) for the Identity type constructor.

This would mean replacing:

type State[A, S] = StateT[Id, A, S]

with:

trait State[A, S] { self =>
// copy-paste starts here...
}

Pros:
- Less demanding on Scala's type inference and implicit search
(although it's holding together pretty well as currently organized)
- Less cognitive burden for users to understand the API and implementation
- Potentially better performance

Cons:
- More code to write
- Difficult to keep the API in sync between the two versions (tools
could help here)

Thoughts?

-jason

Chris Marshall

unread,
Apr 21, 2012, 1:29:17 PM4/21/12
to sca...@googlegroups.com
This is actually why I had assumed that scalaz7 was going to be majorly source-incompatible. It took me ages to find where State had gone and, when I found it, I thought: "huh?". I think I am going to have a hard time understanding how to use this (as I've not used monad-transformers yet), however I *don't* think this is a good reason to go down the route of copy & paste and trying to manage the resulting duplication.

Keep it as is; put more effort into gists full of examples (or blog posts) for soft-in-the-head-types like me.

Chris


-jason

--
You received this message because you are subscribed to the Google Groups "scalaz" group.
To post to this group, send email to sca...@googlegroups.com.
To unsubscribe from this group, send email to scalaz+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scalaz?hl=en.


Tony Morris

unread,
Apr 22, 2012, 4:47:20 AM4/22/12
to sca...@googlegroups.com
I am strongly against it. The only "Pro" that I accept is for Scala type
inference and it is nowhere near worth it. I disagree there is less
cognitive burden for users (indeed, I would argue the contrary if
forced). If performance is an issue because we use polymorphism, I'd
rather just write a new language and runtime.

The "Cons" should take into account that "More code to write" is not
linear -- but goes on for each dependency.


--
Tony Morris
http://tmorris.net/


Jason Zaugg

unread,
Apr 22, 2012, 7:35:02 AM4/22/12
to sca...@googlegroups.com
On Sun, Apr 22, 2012 at 10:47 AM, Tony Morris <tonym...@gmail.com> wrote:
> I am strongly against it. The only "Pro" that I accept is for Scala type
> inference and it is nowhere near worth it.

> I disagree there is less cognitive burden for users (indeed, I would
> argue the contrary if forced).

My concern is that readers of your lens paper, or Functional
Programming in Scala, will struggle to use the more general form of
these data structures. Perhaps this can be allayed through
documentation/tutorials, as Chris suggests.

> If performance is an issue because we use polymorphism, I'd
> rather just write a new language and runtime.

Scalaz is a library for Scala and the JVM, and I'm interested in the
making the best tradeoffs for these, not for a hypothetical platform.
That said, the performance impact for indirecting through the type
class instance for Id is likely to be acceptable in a lot of cases, so
let's focus on the other points.

> The "Cons" should take into account that "More code to write" is not
> linear -- but goes on for each dependency.

Can you elaborate? I was figuring on a factor of two increase in code size.

-jason

Tony Morris

unread,
Apr 22, 2012, 6:17:53 PM4/22/12
to sca...@googlegroups.com
On 22/04/12 21:35, Jason Zaugg wrote:
> On Sun, Apr 22, 2012 at 10:47 AM, Tony Morris <tonym...@gmail.com> wrote:
>> I am strongly against it. The only "Pro" that I accept is for Scala type
>> inference and it is nowhere near worth it.
>> I disagree there is less cognitive burden for users (indeed, I would
>> argue the contrary if forced).
> My concern is that readers of your lens paper, or Functional
> Programming in Scala, will struggle to use the more general form of
> these data structures. Perhaps this can be allayed through
> documentation/tutorials, as Chris suggests.

I agree there might be some initial struggle for many people, but I also
agree that there would be some additional initial struggle for those in
its specialised form.

We have surely all seen by now how for some people, presenting the list
reversal of integers as [A]List[A] => List[A] is *easier* to understand
because the type signature clearly says that nothing integerish is
happening, yet for others, List[Int] => List[Int] is more concrete,
despite conveying excess information.

I think then, the question is to ask, which is less clumsy overall? I
think all those who have a non-elementary understanding of List.reverse
will agree that List[A] => List[A] is most appropriate. For those
occasions where learning progress is difficult due to the polymorphism,
let us construct teaching aides according. I don't think we should
change our *code* accordingly. After all, what would we do? def
intReverse = reverse[Int]?

In short, I don't agree there is less cognitive burden for users, but I
also don't agree there is more -- it is specific to the individual and
therefore, I am (as always) inclined to apply a different set of
criteria, all of which lead me to "leave it be."


>> If performance is an issue because we use polymorphism, I'd
>> rather just write a new language and runtime.
> Scalaz is a library for Scala and the JVM, and I'm interested in the
> making the best tradeoffs for these, not for a hypothetical platform.
> That said, the performance impact for indirecting through the type
> class instance for Id is likely to be acceptable in a lot of cases, so
> let's focus on the other points.

Sure. I don't know the performance impact either way.

>> The "Cons" should take into account that "More code to write" is not
>> linear -- but goes on for each dependency.
> Can you elaborate? I was figuring on a factor of two increase in code size.
>
> -jason
>

I may have misspoken a bit with that metric, but I guess I am not
looking forward to authoring two versions of just about every data type,
even outside of Scalaz. I mean, it's not just State, Reader and friends
-- this is an infinite list and in practice, one that we would need to
be dealt with constantly in application code.

etorreborre

unread,
Apr 22, 2012, 6:30:56 PM4/22/12
to sca...@googlegroups.com
  trait State[A, S] { self => 
    // copy-paste starts here... 
  } 

You don't necessarily need to copy-paste everything, just the interface. You can delegate the implementation to StateT[Id, A, S].

Eric.

Jason Zaugg

unread,
Apr 23, 2012, 11:23:02 AM4/23/12
to sca...@googlegroups.com
On Monday, April 23, 2012 12:30:56 AM UTC+2, etorreborre wrote:
  trait State[A, S] { self => 
    // copy-paste starts here... 
  } 

You don't necessarily need to copy-paste everything, just the interface. You can delegate the implementation to StateT[Id, A, S].

Eric.

Actually, I'm toying with another approach, in the hope of a having-your-cake-and-eating-it-too solution.

  class Lens[A, B] extends LensT[Id, Id, A, B] {
    // optimized versions of methods could go here that can assume properties of scalaz.idInstance.
  }

Unfortunately, the Scaladoc for Lens doesn't inline the Id type constructor, but perhaps we could patch it to do as much.

It does get a bit awkward in places, as LensT[Id, Id, X, Y] doesn't conform to Lens[X, Y]. But I'll push it a bit further and publish a branch.

-jason

Matthew Pocock

unread,
Apr 23, 2012, 4:14:10 PM4/23/12
to sca...@googlegroups.com


On 21 April 2012 17:12, Jason Zaugg <jza...@gmail.com> wrote:
 
Pros:
 - Potentially better performance
 
If this truly is a problem problem in practice (it should be OK except in critical loops where for whatever reason the typeclass can't be inlined), I would hope that this would go away in the future if there was the option to unroll known typeclass instances at compile-time using macros.


Cons:
 - More code to write
 - Difficult to keep the API in sync between the two versions (tools
could help here)

Big eugh. Manually keeping 2 copies of code in sync is a PITA, and only ever gets worse.

There is a problem for new users that it may not be obvious that the FooT type classes have Foo type aliases. I don't know how much a mix of scaladoc and examples would help here.

Matthew

Thoughts?

-jason

--
You received this message because you are subscribed to the Google Groups "scalaz" group.
To post to this group, send email to sca...@googlegroups.com.
To unsubscribe from this group, send email to scalaz+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scalaz?hl=en.




--
Dr Matthew Pocock
Integrative Bioinformatics Group, School of Computing Science, Newcastle University
skype: matthew.pocock
tel: (0191) 2566550

Tony Morris

unread,
Apr 23, 2012, 6:51:31 PM4/23/12
to sca...@googlegroups.com
Can we not make Id a value class when the time is right?

Jason Zaugg

unread,
Apr 24, 2012, 1:44:24 AM4/24/12
to sca...@googlegroups.com
On Tue, Apr 24, 2012 at 12:51 AM, Tony Morris <tonym...@gmail.com> wrote:
> Can we not make Id a value class when the time is right?

That would require manual unwrapping; I don't think there is a benefit
over the identity type constructor.

-jason

Runar Bjarnason

unread,
May 9, 2012, 4:57:25 PM5/9/12
to sca...@googlegroups.com
What is the benefit of LensT over Lens? It adds a great deal of overhead, and subverts the lens laws. Are there any useful applications of LensT?

Runar

Tony Morris

unread,
May 9, 2012, 5:03:52 PM5/9/12
to sca...@googlegroups.com

I have similar reservations. However, we recently had a use case where I wanted to compose partial lenses and determine which of them failed. Essentially I wanted Writer in the result of the application to the target object, with the W value having access to the lens parameters.

While I do have issues with LensT I only spent a short amount of time coming up with an alternative solution that satisfied requirements. Suggestions welcome.

Note that yall (hackage) models lens similarly.

--
You received this message because you are subscribed to the Google Groups "scalaz" group.
To view this discussion on the web visit https://groups.google.com/d/msg/scalaz/-/FVdz4sVisJMJ.

Runar Bjarnason

unread,
May 9, 2012, 5:11:12 PM5/9/12
to sca...@googlegroups.com
How about

LensT[W[_], A, B] ~= A => W[Costate[B, A]]

Does that meet the requirement? Note that W should be a comonad.

Runar

Tony Morris

unread,
May 9, 2012, 5:59:49 PM5/9/12
to sca...@googlegroups.com

I started off with that then found the BijectionT morphism to the Lens category a bit ugly. I'm totally on the fence and feel your pain. Further opinions welcome.

Tony Morris

unread,
May 11, 2012, 10:14:45 AM5/11/12
to sca...@googlegroups.com

I might revert back to this middle ground next week, run with it and see how we go.

Tony Morris

unread,
May 30, 2012, 2:13:53 AM5/30/12
to sca...@googlegroups.com
Done.
https://github.com/scalaz/scalaz/commit/e15f46e7d49584d8c7b96a2bf775b1387d826b10

PS: I don't see why W must be a comonad when there is already a monad (A =>) sitting on top.
Reply all
Reply to author
Forward
0 new messages