[scala] Bounds in higher-ranked type arguments

View: Old framed views
15 Messages — Rating Filter:   Alert me  
tmorris
[scala] Bounds in higher-ranked type arguments
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I am trying to maintain the covariance of the F type argument below, but
I am running into problems trying to specify the bounds of FF. Is what I
am attempting possible?

trait Functor[F[_]] {
  def map[A, B, FF[_] >: F[_]](ft: => F[A], f: => A => B): FF[B]
}

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

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFHgt5PmnpgrYe6r60RAtACAJ4j5qgOJFWbSCn0x9/sfrWUoZ9WRQCfYENL
svMHgdkJH0J6veQS9scdV7o=
=/wnP
-----END PGP SIGNATURE-----
Andrew.Foggin
Re: [scala] Bounds in higher-ranked type arguments
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
tmorris wrote:
I am trying to maintain the covariance of the F type argument below, but
I am running into problems trying to specify the bounds of FF. Is what I
am attempting possible?

trait Functor[F[_]] {
  def map[A, B, FF[_] >: F[_]](ft: => F[A], f: => A => B): FF[B]
}
I'm not sure I can properly answer you question, but for comparison this is the definition for Functor that I've been using (derived from Adriaan's approach):

  trait Functor[+A, M[+_]] {
    self : M[A] =>
    def map[B >: A](f : A => B) : M[B]
  }

I can't even remember now why I had to have [B >: A] but I just drop the bound for the definition of map in Monad:

  def map[B](f : A => B) = flatMap { a => unit(f(a)) }

All the code is here: http://scala-rules.googlecode.com/svn/trunk/scala-rules/src/net/foggin/rules/Monad.scala

I know your approach is quite different but it may be of some use anyway...

--Andrew
Matt Hellige
Re: [scala] Bounds in higher-ranked type arguments
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
On Jan 7, 2008 8:22 PM, Tony Morris <tmorris@...> wrote:
>
> I am trying to maintain the covariance of the F type argument below, but
> I am running into problems trying to specify the bounds of FF. Is what I
> am attempting possible?
>
> trait Functor[F[_]] {
>   def map[A, B, FF[_] >: F[_]](ft: => F[A], f: => A => B): FF[B]
> }
>

I'm not sure if this is exactly what you want (I think I see what you
mean by covariance, but I'm not sure), but the following seems to
work:
  trait Functor[F[_]] {
    def map[A, B, FF[X] >: F[X]](ft: => F[A], f: => A => B): FF[B]
  }
Remember that FF[_] >: F[_] does not enforce that the two wildcards
match. The second is expanded to an existential (I believe this came
up on the list recently). You need to introduce a variable (X above)
to enforce a match.

Does that help? If not, can you explain further what you mean?

Matt

--
Matt Hellige / matt@...
http://matt.immute.net
tmorris
Re: [scala] Bounds in higher-ranked type arguments
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

That's exactly what I want! Thanks Matt.

Tony Morris
http://tmorris.net/



Matt Hellige wrote:

> On Jan 7, 2008 8:22 PM, Tony Morris <tmorris@...> wrote:
>> I am trying to maintain the covariance of the F type argument below, but
>> I am running into problems trying to specify the bounds of FF. Is what I
>> am attempting possible?
>>
>> trait Functor[F[_]] {
>>   def map[A, B, FF[_] >: F[_]](ft: => F[A], f: => A => B): FF[B]
>> }
>>
>
> I'm not sure if this is exactly what you want (I think I see what you
> mean by covariance, but I'm not sure), but the following seems to
> work:
>   trait Functor[F[_]] {
>     def map[A, B, FF[X] >: F[X]](ft: => F[A], f: => A => B): FF[B]
>   }
> Remember that FF[_] >: F[_] does not enforce that the two wildcards
> match. The second is expanded to an existential (I believe this came
> up on the list recently). You need to introduce a variable (X above)
> to enforce a match.
>
> Does that help? If not, can you explain further what you mean?
>
> Matt
>
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFHgvDemnpgrYe6r60RAvmBAKDB9I1rIn8SCdAKsFQVUUTpdxMODQCgw1PK
vYQjh3ZbcjXQGmi3Y3KL760=
=rqDU
-----END PGP SIGNATURE-----
Amir Michail
Re: [scala] Bounds in higher-ranked type arguments
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
On Jan 7, 2008 10:37 PM, Matt Hellige <matt@...> wrote:

> On Jan 7, 2008 8:22 PM, Tony Morris <tmorris@...> wrote:
> >
> > I am trying to maintain the covariance of the F type argument below, but
> > I am running into problems trying to specify the bounds of FF. Is what I
> > am attempting possible?
> >
> > trait Functor[F[_]] {
> >   def map[A, B, FF[_] >: F[_]](ft: => F[A], f: => A => B): FF[B]
> > }
> >
>
> I'm not sure if this is exactly what you want (I think I see what you
> mean by covariance, but I'm not sure), but the following seems to
> work:
>   trait Functor[F[_]] {
>     def map[A, B, FF[X] >: F[X]](ft: => F[A], f: => A => B): FF[B]
>   }

Is it possible to use more self-explanatory notation for something
like this? It would be nice if people not familiar with Scala could at
least make a reasonable guess as to what the code does.

Amir

> Remember that FF[_] >: F[_] does not enforce that the two wildcards
> match. The second is expanded to an existential (I believe this came
> up on the list recently). You need to introduce a variable (X above)
> to enforce a match.
>
> Does that help? If not, can you explain further what you mean?
>
> Matt
>
> --
> Matt Hellige / matt@...
> http://matt.immute.net
>
tmorris
Re: [scala] Bounds in higher-ranked type arguments
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Andrew,
After many unsuccessful attempts to get what I *really* want out of the
scalaz.control library (abstraction without penalty), I have succumbed
to the possibility that I may need to rewrite it using self-types.

Is this the recommended approach? I'd be interested in Adriaan's
comments here.

I believe that Scala needs such types to represent Monads, Functors,
Catamorphisms, Anamorphisms and Paramorphisms, etc. but I always seem to
struggle with Scala's apparent persistence with objects and not merely
functions.

I am now seeking recommendations from others who may have a more
intimate understanding of the issues at hand. Thanks.

Thanks for any pointers.

Tony Morris
http://tmorris.net/



Andrew Foggin (h) wrote:

>
> tmorris wrote:
>> I am trying to maintain the covariance of the F type argument below, but
>> I am running into problems trying to specify the bounds of FF. Is what I
>> am attempting possible?
>>
>> trait Functor[F[_]] {
>>   def map[A, B, FF[_] >: F[_]](ft: => F[A], f: => A => B): FF[B]
>> }
>>
>
> I'm not sure I can properly answer you question, but for comparison this is
> the definition for Functor that I've been using (derived from Adriaan's
> approach):
>
>   trait Functor[+A, M[+_]] {
>     self : M[A] =>
>     def map[B >: A](f : A => B) : M[B]
>   }
>
> I can't even remember now why I had to have [B >: A] but I just drop the
> bound for the definition of map in Monad:
>
>   def map[B](f : A => B) = flatMap { a => unit(f(a)) }
>
> All the code is here:
> http://scala-rules.googlecode.com/svn/trunk/scala-rules/src/net/foggin/rules/Monad.scala
>
> I know your approach is quite different but it may be of some use anyway...
>
> --Andrew
>
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFHipmKmnpgrYe6r60RAs9RAKCi/Pp+39X4JGR2zRo0JW9Q/lyVBACgk+7b
BlltjCYdZCQGSlRJY3q5g6o=
=e/+R
-----END PGP SIGNATURE-----
Matt Hellige
Re: [scala] Bounds in higher-ranked type arguments
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
Tony...

It seems like you're mostly struggling with the trade-offs between the
different ways of encoding type classes in Scala, but I'm not totally
sure I understand you. Is that what you're getting at? If so, I know
some of the encodings, and some of their pros/cons, but I would love
to hear more about your experience. If you have the time to elaborate
on the difficulties you've encountered and what you're trying to
accomplish, I'd really appreciate it. In particular, I'm curious which
of the following are sources of trouble:
  (a) inability to partially apply type constructors
  (b) verbosity
  (c) subtyping
  (d) all/other
Do you think similar problems would arise in a Haskell with subtyping?
You've pushed Scala pretty hard in this direction, so I'm quite
curious about your findings. Maybe I've misunderstood you completely,
in which case I'd love it if you'd elaborate.

Thanks...
Matt

On Jan 13, 2008 5:06 PM, Tony Morris <tmorris@...> wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hi Andrew,
> After many unsuccessful attempts to get what I *really* want out of the
> scalaz.control library (abstraction without penalty), I have succumbed
> to the possibility that I may need to rewrite it using self-types.
>
> Is this the recommended approach? I'd be interested in Adriaan's
> comments here.
>
> I believe that Scala needs such types to represent Monads, Functors,
> Catamorphisms, Anamorphisms and Paramorphisms, etc. but I always seem to
> struggle with Scala's apparent persistence with objects and not merely
> functions.
>
> I am now seeking recommendations from others who may have a more
> intimate understanding of the issues at hand. Thanks.
>
> Thanks for any pointers.
>
> Tony Morris
> http://tmorris.net/
>
>
>
> Andrew Foggin (h) wrote:
> >
> > tmorris wrote:
> >> I am trying to maintain the covariance of the F type argument below, but
> >> I am running into problems trying to specify the bounds of FF. Is what I
> >> am attempting possible?
> >>
> >> trait Functor[F[_]] {
> >>   def map[A, B, FF[_] >: F[_]](ft: => F[A], f: => A => B): FF[B]
> >> }
> >>
> >
> > I'm not sure I can properly answer you question, but for comparison this is
> > the definition for Functor that I've been using (derived from Adriaan's
> > approach):
> >
> >   trait Functor[+A, M[+_]] {
> >     self : M[A] =>
> >     def map[B >: A](f : A => B) : M[B]
> >   }
> >
> > I can't even remember now why I had to have [B >: A] but I just drop the
> > bound for the definition of map in Monad:
> >
> >   def map[B](f : A => B) = flatMap { a => unit(f(a)) }
> >
> > All the code is here:
> > http://scala-rules.googlecode.com/svn/trunk/scala-rules/src/net/foggin/rules/Monad.scala
> >
> > I know your approach is quite different but it may be of some use anyway...
> >
> > --Andrew
> >
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.6 (GNU/Linux)
> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
>
> iD8DBQFHipmKmnpgrYe6r60RAs9RAKCi/Pp+39X4JGR2zRo0JW9Q/lyVBACgk+7b
> BlltjCYdZCQGSlRJY3q5g6o=
> =e/+R
> -----END PGP SIGNATURE-----
>



--
Matt Hellige / matt@...
http://matt.immute.net
tmorris
Re: [scala] Bounds in higher-ranked type arguments
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Matt,
I'd love to respond to your questions, since you are definitely
understanding me completely given your list of a, b, c and d.

I will consider how to respond when I think it through.

I will say however, I have tried all combinations of suggestions so far
and I have not moved from where I was, since they all introduced
problems that I was not prepared to accept.

I'll get back to you in a more detailed way.

Tony Morris
http://tmorris.net/



Matt Hellige wrote:

> Tony...
>
> It seems like you're mostly struggling with the trade-offs between the
> different ways of encoding type classes in Scala, but I'm not totally
> sure I understand you. Is that what you're getting at? If so, I know
> some of the encodings, and some of their pros/cons, but I would love
> to hear more about your experience. If you have the time to elaborate
> on the difficulties you've encountered and what you're trying to
> accomplish, I'd really appreciate it. In particular, I'm curious which
> of the following are sources of trouble:
>   (a) inability to partially apply type constructors
>   (b) verbosity
>   (c) subtyping
>   (d) all/other
> Do you think similar problems would arise in a Haskell with subtyping?
> You've pushed Scala pretty hard in this direction, so I'm quite
> curious about your findings. Maybe I've misunderstood you completely,
> in which case I'd love it if you'd elaborate.
>
> Thanks...
> Matt
>
> On Jan 13, 2008 5:06 PM, Tony Morris <tmorris@...> wrote:
> Hi Andrew,
> After many unsuccessful attempts to get what I *really* want out of the
> scalaz.control library (abstraction without penalty), I have succumbed
> to the possibility that I may need to rewrite it using self-types.
>
> Is this the recommended approach? I'd be interested in Adriaan's
> comments here.
>
> I believe that Scala needs such types to represent Monads, Functors,
> Catamorphisms, Anamorphisms and Paramorphisms, etc. but I always seem to
> struggle with Scala's apparent persistence with objects and not merely
> functions.
>
> I am now seeking recommendations from others who may have a more
> intimate understanding of the issues at hand. Thanks.
>
> Thanks for any pointers.
>
> Tony Morris
> http://tmorris.net/
>
>
>
> Andrew Foggin (h) wrote:
>>>> tmorris wrote:
>>>>> I am trying to maintain the covariance of the F type argument below, but
>>>>> I am running into problems trying to specify the bounds of FF. Is what I
>>>>> am attempting possible?
>>>>>
>>>>> trait Functor[F[_]] {
>>>>>   def map[A, B, FF[_] >: F[_]](ft: => F[A], f: => A => B): FF[B]
>>>>> }
>>>>>
>>>> I'm not sure I can properly answer you question, but for comparison this is
>>>> the definition for Functor that I've been using (derived from Adriaan's
>>>> approach):
>>>>
>>>>   trait Functor[+A, M[+_]] {
>>>>     self : M[A] =>
>>>>     def map[B >: A](f : A => B) : M[B]
>>>>   }
>>>>
>>>> I can't even remember now why I had to have [B >: A] but I just drop the
>>>> bound for the definition of map in Monad:
>>>>
>>>>   def map[B](f : A => B) = flatMap { a => unit(f(a)) }
>>>>
>>>> All the code is here:
>>>> http://scala-rules.googlecode.com/svn/trunk/scala-rules/src/net/foggin/rules/Monad.scala
>>>>
>>>> I know your approach is quite different but it may be of some use anyway...
>>>>
>>>> --Andrew
>>>>
>>

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFHjD4zmnpgrYe6r60RAil7AJ4vlTaHapXDZ2Z7CPRN4WX50aUDhACfUhxu
TkrKN+zMhjAhTOVmdQDQSgo=
=fSyJ
-----END PGP SIGNATURE-----
Andrew.Foggin
A trait for monads (was Re: [scala] Bounds in higher-ranked type arguments)
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
I have come up with something that is very simple but seems to work OK
for me:


trait Monads {
  type M[+A]
 
  def unit[A](a : => A) : M[A]
  def zero : M[Nothing] = error("zero not defined")
 
  trait Functor[+A] { self : M[A] =>
    def map[B](f : A => B) : M[B]
  }
 
  trait Monad[+A] extends Functor[A] { self : M[A] =>
    def flatMap[B](f : A => M[B]) : M[B]
    def map[B](f : A => B) = flatMap { a => unit(f(a)) }
    def filter[B >: A](f : A => Boolean) = flatMap { a => if (f(a))
unit(a) else zero }
  }

  trait MonadWithPlus[+A] extends Monad[A] { self : M[A] =>
    def plus[B >: A](other : => M[B]) : M[B]
  }
 
  trait Zero extends MonadWithPlus[Nothing] { self : M[Nothing] =>
    def plus[B](other : => M[B]) = other
    def flatMap[B](f : Nothing => M[B]) : M[B] = this
  }
}


As a simple example here's how Option could be constructed using this trait:

  object Option extends Monads {
    type M[+A] = Option[A]
    def unit[A](a : => A) = Some(a)
    override def zero = None
  }
 
  sealed abstract class Option[+A] extends Option.MonadWithPlus[A]

  case class Some[+A](value : A) extends Option[A] {
    def flatMap[B](f : A => Option[B]) = f(value)
    def plus[B >: A](other : => Option[B]) = this
  }

  case object None extends Option[Nothing] with Option.Zero


What do you think?

Regards,

Andrew Foggin



Tony Morris wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hi Andrew,
> After many unsuccessful attempts to get what I *really* want out of the
> scalaz.control library (abstraction without penalty), I have succumbed
> to the possibility that I may need to rewrite it using self-types.
>
> Is this the recommended approach? I'd be interested in Adriaan's
> comments here.
>
> I believe that Scala needs such types to represent Monads, Functors,
> Catamorphisms, Anamorphisms and Paramorphisms, etc. but I always seem to
> struggle with Scala's apparent persistence with objects and not merely
> functions.
>
> I am now seeking recommendations from others who may have a more
> intimate understanding of the issues at hand. Thanks.
>
> Thanks for any pointers.
>
> Tony Morris
> http://tmorris.net/
>
>
>
> Andrew Foggin (h) wrote:
>  
>> tmorris wrote:
>>    
>>> I am trying to maintain the covariance of the F type argument below, but
>>> I am running into problems trying to specify the bounds of FF. Is what I
>>> am attempting possible?
>>>
>>> trait Functor[F[_]] {
>>>   def map[A, B, FF[_] >: F[_]](ft: => F[A], f: => A => B): FF[B]
>>> }
>>>
>>>      
>> I'm not sure I can properly answer you question, but for comparison this is
>> the definition for Functor that I've been using (derived from Adriaan's
>> approach):
>>
>>   trait Functor[+A, M[+_]] {
>>     self : M[A] =>
>>     def map[B >: A](f : A => B) : M[B]
>>   }
>>
>> I can't even remember now why I had to have [B >: A] but I just drop the
>> bound for the definition of map in Monad:
>>
>>   def map[B](f : A => B) = flatMap { a => unit(f(a)) }
>>
>> All the code is here:
>> http://scala-rules.googlecode.com/svn/trunk/scala-rules/src/net/foggin/rules/Monad.scala
>>
>> I know your approach is quite different but it may be of some use anyway...
>>
>> --Andrew
>>
>>    
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.6 (GNU/Linux)
> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
>
> iD8DBQFHipmKmnpgrYe6r60RAs9RAKCi/Pp+39X4JGR2zRo0JW9Q/lyVBACgk+7b
> BlltjCYdZCQGSlRJY3q5g6o=
> =e/+R
> -----END PGP SIGNATURE-----
>
>  

tmorris
Re: A trait for monads (was Re: [scala] Bounds in higher-ranked type arguments)
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Andrew Foggin wrote:

> I have come up with something that is very simple but seems to work OK
> for me:
>
>
> trait Monads {
>  type M[+A]
>
>  def unit[A](a : => A) : M[A]
>  def zero : M[Nothing] = error("zero not defined")
>
>  trait Functor[+A] { self : M[A] =>
>    def map[B](f : A => B) : M[B]
>  }
>
>  trait Monad[+A] extends Functor[A] { self : M[A] =>
>    def flatMap[B](f : A => M[B]) : M[B]
>    def map[B](f : A => B) = flatMap { a => unit(f(a)) }
>    def filter[B >: A](f : A => Boolean) = flatMap { a => if (f(a))
> unit(a) else zero }
>  }
>
>  trait MonadWithPlus[+A] extends Monad[A] { self : M[A] =>
>    def plus[B >: A](other : => M[B]) : M[B]
>  }
>
>  trait Zero extends MonadWithPlus[Nothing] { self : M[Nothing] =>
>    def plus[B](other : => M[B]) = other
>    def flatMap[B](f : Nothing => M[B]) : M[B] = this
>  }
> }
>
>
> As a simple example here's how Option could be constructed using this
> trait:
>
>  object Option extends Monads {
>    type M[+A] = Option[A]
>    def unit[A](a : => A) = Some(a)
>    override def zero = None
>  }
>
>  sealed abstract class Option[+A] extends Option.MonadWithPlus[A]
>
>  case class Some[+A](value : A) extends Option[A] {
>    def flatMap[B](f : A => Option[B]) = f(value)
>    def plus[B >: A](other : => Option[B]) = this
>  }
>
>  case object None extends Option[Nothing] with Option.Zero
>
>
> What do you think?
>
> Regards,
>
> Andrew Foggin

This would require me to 'newtype' each time I want to instance Monad
(or whatever) right? Suppose I have some type T whose source I cannot
modify, I would not be able to declare T an instance of any of the
above, correct? I find this to be a limitation (the same I have been
accepting for quite some time now), especially given the
non-transitivity limitation of implicit defs.

Ultimately, I have it down to "the explicit need to apply the
higher-ranked type argument with a newtype/PIMP", which is not very
nice, but annoyingly redundant nonetheless. Perhaps I should write all
this up as per Matt's request.

I have also done away with subclassing, since I prefer the more
'type-class' approach, despite once again, the lack of transitivity of
implicits. For example, Monad is an abstract class that accepts an
implicit Functor argument.

Regarding, MonadWithZero, you might consider splitting into two
different traits that follow different laws. I am an advocate of fixing
one of Haskell's mistakes (and not repeating it in Scala):

http://www.haskell.org/haskellwiki/MonadPlus_reform_proposal



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

Hey! We had 40,000 lines of C# here yesterday, but now there are 40
lines of... Dear God, what is a catamorphism?"
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFHk6XemnpgrYe6r60RAmkXAJ9zlaZ+oGthg3QXhRWNGVNiC0JR1QCeIewd
PSBsmyAgGVq35IwkK2WsaAk=
=91LB
-----END PGP SIGNATURE-----
Andrew.Foggin
Re: A trait for monads (was Re: [scala] Bounds in higher-ranked type arguments)
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
Tony Morris wrote:
> This would require me to 'newtype' each time I want to instance Monad
> (or whatever) right? Suppose I have some type T whose source I cannot
> modify, I would not be able to declare T an instance of any of the
> above, correct? I find this to be a limitation (the same I have been
> accepting for quite some time now), especially given the
> non-transitivity limitation of implicit defs.
>  

I'm not sure I understand the problem.  Do you have a simple example of
what you would like to do? (in Scala if possible, as I'm not familiar
with Haskell)

> Ultimately, I have it down to "the explicit need to apply the
> higher-ranked type argument with a newtype/PIMP", which is not very
> nice, but annoyingly redundant nonetheless. Perhaps I should write all
> this up as per Matt's request.
>  

Yes please!

> I have also done away with subclassing, since I prefer the more
> 'type-class' approach, despite once again, the lack of transitivity of
> implicits. For example, Monad is an abstract class that accepts an
> implicit Functor argument.
>  

This feels to me a little like cutting across the grain of the language...

> Regarding, MonadWithZero, you might consider splitting into two
> different traits that follow different laws. I am an advocate of fixing
> one of Haskell's mistakes (and not repeating it in Scala):
>
> http://www.haskell.org/haskellwiki/MonadPlus_reform_proposal
>
>
>  
Very good point!  Here's the result:

trait Monads {
  type M[+A]
 
  def unit[A](a : => A) : M[A]
  def zero : M[Nothing] = error("zero not defined")
 
  trait Functor[+A] { self : M[A] =>
    def map[B](f : A => B) : M[B]
  }
 
  trait Monad[+A] extends Functor[A] { self : M[A] =>
    def flatMap[B](f : A => M[B]) : M[B]
    def map[B](f : A => B) = flatMap { a => unit(f(a)) }
    def filter[B >: A](f : A => Boolean) = flatMap { a => if (f(a))
unit(a) else zero }
  }

  trait Plus[+A] { self : M[A] =>
    def plus[B >: A](other : => M[B]) : M[B]
  }
 
  trait OrElse[+A] { self : M[A] =>
    def orElse[B >: A](other : => M[B]) : M[B]
  }

  trait Zero extends Monad[Nothing] { self : M[Nothing] =>
    def flatMap[B](f : Nothing => M[B]) : M[B] = this
  }

  trait ZeroPlus extends Zero with Plus[Nothing] { self : M[Nothing] =>
    def plus[B](other : => M[B]) = other
  }

  trait ZeroOrElse extends Zero with OrElse[Nothing] { self : M[Nothing] =>
    def orElse[B](other : => M[B]) = other
  }
}

-- Andrew
tmorris
Re: A trait for monads (was Re: [scala] Bounds in higher-ranked type arguments)
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Andrew Foggin wrote:

> Tony Morris wrote:
>> This would require me to 'newtype' each time I want to instance Monad
>> (or whatever) right? Suppose I have some type T whose source I cannot
>> modify, I would not be able to declare T an instance of any of the
>> above, correct? I find this to be a limitation (the same I have been
>> accepting for quite some time now), especially given the
>> non-transitivity limitation of implicit defs.
>>  
>
> I'm not sure I understand the problem.  Do you have a simple example of
> what you would like to do? (in Scala if possible, as I'm not familiar
> with Haskell)

How are you proposing we get an instance of Monad for Option? Does this
require you to "PIMP" the existing Option? If not, then great! But I
can't see how. I'm really just trying to minimise the burden on the
client in both syntax and "instancing".

>
>> Ultimately, I have it down to "the explicit need to apply the
>> higher-ranked type argument with a newtype/PIMP", which is not very
>> nice, but annoyingly redundant nonetheless. Perhaps I should write all
>> this up as per Matt's request.
>>  
>
> Yes please!

/me purchases a block of spare time ;)

>
>> I have also done away with subclassing, since I prefer the more
>> 'type-class' approach, despite once again, the lack of transitivity of
>> implicits. For example, Monad is an abstract class that accepts an
>> implicit Functor argument.
>>  
>
> This feels to me a little like cutting across the grain of the language...

I agree and I haven't concluded that this solution is best yet.

>
>> Regarding, MonadWithZero, you might consider splitting into two
>> different traits that follow different laws. I am an advocate of fixing
>> one of Haskell's mistakes (and not repeating it in Scala):
>>
>> http://www.haskell.org/haskellwiki/MonadPlus_reform_proposal
>>
>>
>>  
> Very good point!  Here's the result:
>
> trait Monads {
>  type M[+A]
>
>  def unit[A](a : => A) : M[A]
>  def zero : M[Nothing] = error("zero not defined")
>
>  trait Functor[+A] { self : M[A] =>
>    def map[B](f : A => B) : M[B]
>  }
>
>  trait Monad[+A] extends Functor[A] { self : M[A] =>
>    def flatMap[B](f : A => M[B]) : M[B]
>    def map[B](f : A => B) = flatMap { a => unit(f(a)) }
>    def filter[B >: A](f : A => Boolean) = flatMap { a => if (f(a))
> unit(a) else zero }
>  }
>
>  trait Plus[+A] { self : M[A] =>
>    def plus[B >: A](other : => M[B]) : M[B]
>  }
>
>  trait OrElse[+A] { self : M[A] =>
>    def orElse[B >: A](other : => M[B]) : M[B]
>  }
>
>  trait Zero extends Monad[Nothing] { self : M[Nothing] =>
>    def flatMap[B](f : Nothing => M[B]) : M[B] = this
>  }
>
>  trait ZeroPlus extends Zero with Plus[Nothing] { self : M[Nothing] =>
>    def plus[B](other : => M[B]) = other
>  }
>
>  trait ZeroOrElse extends Zero with OrElse[Nothing] { self : M[Nothing] =>
>    def orElse[B](other : => M[B]) = other
>  }
> }

Looking good ;)
Why is zero on monad and not Zero?

I was thinking of a hierarchy as follows:

Functor
Monad extends Functor
MonadZero extends Monad
MonadPlus extends MonadZero
MonadOrElse extends MonadZero

>
> -- Andrew
>
>
>


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

Hey! We had 40,000 lines of C# here yesterday, but now there are 40
lines of... Dear God, what is a catamorphism?"
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFHlPvzmnpgrYe6r60RAs9VAJwL1xmp3jyoUIVOjA0+mudJl4htxgCbBARQ
ZNfnXYp631+xQiuLK0jzSns=
=KVoX
-----END PGP SIGNATURE-----
Matt Hellige
Re: A trait for monads (was Re: [scala] Bounds in higher-ranked type arguments)
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
On Jan 21, 2008 2:09 PM, Tony Morris <tmorris@...> wrote:
>
> Andrew Foggin wrote:
> >
> > This feels to me a little like cutting across the grain of the language...
>
> I agree and I haven't concluded that this solution is best yet.
>

I'm not so sure. It certainly cuts across the grain of current
practice, and the grain of the libraries. But I think it takes a long
time to discern the grain of a language. And I think it takes a lot of
pushing and prodding, which is why I think this kind of
experimentation is so important.

For now, it's a reasonable default to stick to a style that reflects
the origins of the language (mostly Java-style OO with some functional
goodies and richer types). But I definitely think we should be open to
the possibility that Scala style will diverge more radically from this
tradition.

Matt

--
Matt Hellige / matt@...
http://matt.immute.net
tmorris
Re: A trait for monads (was Re: [scala] Bounds in higher-ranked type arguments)
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Matt Hellige wrote:

> On Jan 21, 2008 2:09 PM, Tony Morris <tmorris@...> wrote:
>> Andrew Foggin wrote:
>>> This feels to me a little like cutting across the grain of the language...
>> I agree and I haven't concluded that this solution is best yet.
>>
>
> I'm not so sure. It certainly cuts across the grain of current
> practice, and the grain of the libraries. But I think it takes a long
> time to discern the grain of a language. And I think it takes a lot of
> pushing and prodding, which is why I think this kind of
> experimentation is so important.
>
> For now, it's a reasonable default to stick to a style that reflects
> the origins of the language (mostly Java-style OO with some functional
> goodies and richer types). But I definitely think we should be open to
> the possibility that Scala style will diverge more radically from this
> tradition.
>
> Matt
>

Funny, I just had a shower thinking about this exact issue :) When I get
to work (it's 0642 here), I will be exploring it further to hopefully
form a loose conclusion i.e. open to critique.

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

Hey! We had 40,000 lines of C# here yesterday, but now there are 40
lines of... Dear God, what is a catamorphism?"
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFHlQPAmnpgrYe6r60RAkSbAJ95XkUydiUlic3/WY3vUDED1u7PrgCgmXYw
9ZcPcFYWdKK7OCMWXx2OYbs=
=W5Cg
-----END PGP SIGNATURE-----
Andrew.Foggin
[scala] Scala style
Reply More
Rate this Message:
Reply to author
Print
Show in thread view
Show in list view (by date)
Permalink
[-scala, +scala-debate]

Tony Morris wrote:

> Matt Hellige wrote:
>  
>> On Jan 21, 2008 2:09 PM, Tony Morris <tmorris@...> wrote:
>>    
>>> Andrew Foggin wrote:
>>>      
>>>> This feels to me a little like cutting across the grain of the language...
>>>>        
>>> I agree and I haven't concluded that this solution is best yet.
>>>
>>>      
>> I'm not so sure. It certainly cuts across the grain of current
>> practice, and the grain of the libraries. But I think it takes a long
>> time to discern the grain of a language. And I think it takes a lot of
>> pushing and prodding, which is why I think this kind of
>> experimentation is so important.
>>
>> For now, it's a reasonable default to stick to a style that reflects
>> the origins of the language (mostly Java-style OO with some functional
>> goodies and richer types). But I definitely think we should be open to
>> the possibility that Scala style will diverge more radically from this
>> tradition.
>>
>> Matt
>>
>>    
>
> Funny, I just had a shower thinking about this exact issue :) When I get
> to work (it's 0642 here), I will be exploring it further to hopefully
> form a loose conclusion i.e. open to critique.
>
>  
It's even earlier on this side of Australia ;-)

Matt makes a good point.  Coming from the Java side, it's already clear
that a good solution in Scala will often look very different to what one
would naturally do in Java (and once you start thinking in Scala it's
very hard to go back to Java :-(  )

I imagine that it's the same from the FP side.  For example Tony's
type-class style approach to the the Monad hierarchy is more heavily
influenced by Haskell.  One problem in this case is that this results in
complicated type-parameter lists containing higher-kinded types, and
Scala's type inferencer doesn't handle this so well...

-- Andrew
LightInTheBox - Buy quality products at wholesale price!