- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Arcane operators (was Re: Traversing data structures)
Mon, 2010-05-10, 02:48
On 7 May 2010 12:26, Tony Morris wrote:
> See scalaz.Traverse or the paper titled, The Essence of the Iterator
> Pattern.
The paper was interesting, thanks.
I had a look, but scalaz.Traverse seems to suffer from the same lack
of documentation as the rest of the library.
I tried reading the source for the Traverse class, but it's full of
arcane operators that I don't understand:
ie. "#::", "∘" & "↦".
Which reminds me - I was looking at the source for another
undocumented library, and it seemed to be all about using a dozen
different odd operators, such as "/:", ">:>" and ">~". (For a few, see
http://databinder.net/dispatch-doc/dispatch/Handlers.html)
I am getting a little worried that Scala is turning into APL or Perl4,
and looking more like line noise than code.
Is this a good thing? Just because you can create and overload any
operators you can imagine, doesn't necessarily mean it's a good idea,
IMHO.
Sorry, that isn't very constructive, but I was thinking about it a lot
over the weekend, and wondered what the crowd wisdom on the matter is.
-Toby
> Toby Corkindale wrote:
>> Hi,
>> I seem to be having to make a lot of effort to traverse some simple
>> data structures, and so wondered if I could ask the crowd for their
>> wisdom.
>>
>> Let's say I have a data structure like this: (as returned by the json
>> parser in scala)
>>
>> Some(
>> List(
>> Map(
>> name -> "The Salisbury",
>> url -> "http://example.com/1"
>> ),
>> Map(
>> name -> "The Foundry",
>> url -> "http://example.com/2"
>> )
>> )
>> )
>>
>>
>> I think the part I'm struggling with most is the Some() wrapped around it.
>>
>> I'm trying to do:
>> jlist.get.asInstanceOf[List[Map[String,String]]].foreach(hotel =>
>> println(hotel(name)))
>>
>> but it's a bit awkward, and worse, doesn't seem to work - I either get
>> errors about things not being members of "Any" class, or deprecation
>> warnings (on 2.8.0.RC1), or that I need to use Option[List[Any]]
>> instead of List[Map[string,string]] but then that fails elsewhere.
>>
>> Is there a simpler way to handle the Some/Any/Option stuff that
>> appears throughout the structure, supposedly?
>>
>>
>> If I was doing this in Perl, the code would be:
>> map { say $_->{name} } @places;
>> which is rather more succinct.
>>
>> Cheers,
>> Toby
Mon, 2010-05-10, 04:07
#2
Re: Arcane operators (was Re: Traversing data structures)
Here we go again, this should be an entertaining thread..... :)
While I do agree with you in principle Tony, in practice, one problem
with this approach to only using typing for documentation is the
problem of discovery:
Say, I want to find out if the standard library has a function of this
type: (implicit Functor[F]) => F[A] => (A => B)
> => F[B]
How can I find it?
Haskell has the absolutely awesome Hoogle
(http://www.haskell.org/hoogle/) which solves this problem quite well,
I don't know of any equivalent for Scala (if there is, please let me
know - I'd be delighted to be wrong!)
Admittedly, the problem exists even for named functions, i.e. if I
don't know the name of the function I am looking for how do I find it
- but hopefully you'd have also write some searchable and indexible
English text in your documentation which might help me find it.
Ishaaq
On 10 May 2010 12:01, Tony Morris wrote:
> Hi Toby,
> Follow The Types.
>
> In my personal opinion, in many of the cases you have given, it is a
> *good thing* that the names convey no "apparent meaning", since to do
> otherwise is quite a detrimental distraction.
>
> For example, ∘ has this type: (implicit Functor[F]) => F[A] => (A => B)
> => F[B] and satisfies two (unenforced) laws: identity and composition.
> *** It's extremely important that no further information is derived in
> order to achieve the appropriate abstraction. *** You'll notice the
> similarity of signature to the canonical Scala name "map" which is at
> least 300% longer than it should be. That's a whopping 300% at a
> minimum! No wonder there is so much distraction. In fact, this is so
> much a distraction, that languages such as DDC/Haskell make this
> function *implicit* such that the name length is zero (i.e. lifting is
> "automatic").
>
> Did you know that scala.Function1 has a map function, except it has this
> name: "andThen." Take a look at the signature:
>
> Function1[T, A] => (A => B) => Function1[T, B]
>
> Notice the similarity to (for example List.map):
>
> List[A] => (A => B) => List[B]
>
> Or perhaps:
>
> Option[A] => (A => B) => Option[B]
>
> Thought provoking?
>
> In any case, this issue of function names is contentious and one that is
> difficult to overcome, especially on the Scala mailing lists (see
> history). Perhaps I can refer you to my young colleague who sits next to
> me, who once strongly believed in the value of function names, but I
> have brainwashed (disciplined) him to the contrary to some extent! haha!
>
> Just joking. In all honesty, I'm in a bind in how to present this
> position in a constructive way, since such efforts often ends in
> bitterness and miscommunication. I must tread lightly, but I am
> otherwise happy to help and I hope this email does in some way.
>
>
> Toby Corkindale wrote:
>> On 7 May 2010 12:26, Tony Morris wrote:
>>
>>> See scalaz.Traverse or the paper titled, The Essence of the Iterator
>>> Pattern.
>>>
>>
>> The paper was interesting, thanks.
>> I had a look, but scalaz.Traverse seems to suffer from the same lack
>> of documentation as the rest of the library.
>> I tried reading the source for the Traverse class, but it's full of
>> arcane operators that I don't understand:
>> ie. "#::", "∘" & "↦".
>>
>> Which reminds me - I was looking at the source for another
>> undocumented library, and it seemed to be all about using a dozen
>> different odd operators, such as "/:", ">:>" and ">~". (For a few, see
>> http://databinder.net/dispatch-doc/dispatch/Handlers.html)
>> I am getting a little worried that Scala is turning into APL or Perl4,
>> and looking more like line noise than code.
>>
>> Is this a good thing? Just because you can create and overload any
>> operators you can imagine, doesn't necessarily mean it's a good idea,
>> IMHO.
>>
>> Sorry, that isn't very constructive, but I was thinking about it a lot
>> over the weekend, and wondered what the crowd wisdom on the matter is.
>>
>> -Toby
>>
>>
>>
>>> Toby Corkindale wrote:
>>>
>>>> Hi,
>>>> I seem to be having to make a lot of effort to traverse some simple
>>>> data structures, and so wondered if I could ask the crowd for their
>>>> wisdom.
>>>>
>>>> Let's say I have a data structure like this: (as returned by the json
>>>> parser in scala)
>>>>
>>>> Some(
>>>> List(
>>>> Map(
>>>> name -> "The Salisbury",
>>>> url -> "http://example.com/1"
>>>> ),
>>>> Map(
>>>> name -> "The Foundry",
>>>> url -> "http://example.com/2"
>>>> )
>>>> )
>>>> )
>>>>
>>>>
>>>> I think the part I'm struggling with most is the Some() wrapped around it.
>>>>
>>>> I'm trying to do:
>>>> jlist.get.asInstanceOf[List[Map[String,String]]].foreach(hotel =>
>>>> println(hotel(name)))
>>>>
>>>> but it's a bit awkward, and worse, doesn't seem to work - I either get
>>>> errors about things not being members of "Any" class, or deprecation
>>>> warnings (on 2.8.0.RC1), or that I need to use Option[List[Any]]
>>>> instead of List[Map[string,string]] but then that fails elsewhere.
>>>>
>>>> Is there a simpler way to handle the Some/Any/Option stuff that
>>>> appears throughout the structure, supposedly?
>>>>
>>>>
>>>> If I was doing this in Perl, the code would be:
>>>> map { say $_->{name} } @places;
>>>> which is rather more succinct.
>>>>
>>>> Cheers,
>>>> Toby
>>>>
>
>
Mon, 2010-05-10, 06:47
#3
Re: Arcane operators (was Re: Traversing data structures)
On 10 May 2010 12:01, Tony Morris wrote:
> Hi Toby,
> Follow The Types.
>
> In my personal opinion, in many of the cases you have given, it is a
> *good thing* that the names convey no "apparent meaning", since to do
> otherwise is quite a detrimental distraction.
[snip example]
> In any case, this issue of function names is contentious and one that is
> difficult to overcome, especially on the Scala mailing lists (see
> history). Perhaps I can refer you to my young colleague who sits next to
> me, who once strongly believed in the value of function names, but I
> have brainwashed (disciplined) him to the contrary to some extent! haha!
>
> Just joking. In all honesty, I'm in a bind in how to present this
> position in a constructive way, since such efforts often ends in
> bitterness and miscommunication. I must tread lightly, but I am
> otherwise happy to help and I hope this email does in some way.
Thanks for the discussion on it so far - you have at least given me
some food for thought on the matter.
Correct me if I'm wrong, but I think I understand your point about
avoiding detrimental distractions as: One should remove wordy
boiler-plate code so as to reduce the size of the code, thus making
the overall code shorter and easier to comprehend, whilst also
becoming agnostic to the reader's native language. Is that correct?
I'm afraid I'm still in the camp of believers in Readable code,
wherein only simple symbols are used, and methods are named such that
even someone who doesn't understand the programming language could
reasonably guess at what is going on.. but perhaps as I come to
understand more of these arcane symbols, I will change my mind.
I don't want to start a flame war, and I guess it's happened before my
time on the list. (I've only been lurking since last year)
yours,
Toby
> Toby Corkindale wrote:
>> On 7 May 2010 12:26, Tony Morris wrote:
>>
>>> See scalaz.Traverse or the paper titled, The Essence of the Iterator
>>> Pattern.
>>>
>>
>> The paper was interesting, thanks.
>> I had a look, but scalaz.Traverse seems to suffer from the same lack
>> of documentation as the rest of the library.
>> I tried reading the source for the Traverse class, but it's full of
>> arcane operators that I don't understand:
>> ie. "#::", "∘" & "↦".
>>
>> Which reminds me - I was looking at the source for another
>> undocumented library, and it seemed to be all about using a dozen
>> different odd operators, such as "/:", ">:>" and ">~". (For a few, see
>> http://databinder.net/dispatch-doc/dispatch/Handlers.html)
>> I am getting a little worried that Scala is turning into APL or Perl4,
>> and looking more like line noise than code.
>>
>> Is this a good thing? Just because you can create and overload any
>> operators you can imagine, doesn't necessarily mean it's a good idea,
>> IMHO.
>>
>> Sorry, that isn't very constructive, but I was thinking about it a lot
>> over the weekend, and wondered what the crowd wisdom on the matter is.
>>
>> -Toby
>>
>>
>>
>>> Toby Corkindale wrote:
>>>
>>>> Hi,
>>>> I seem to be having to make a lot of effort to traverse some simple
>>>> data structures, and so wondered if I could ask the crowd for their
>>>> wisdom.
>>>>
>>>> Let's say I have a data structure like this: (as returned by the json
>>>> parser in scala)
>>>>
>>>> Some(
>>>> List(
>>>> Map(
>>>> name -> "The Salisbury",
>>>> url -> "http://example.com/1"
>>>> ),
>>>> Map(
>>>> name -> "The Foundry",
>>>> url -> "http://example.com/2"
>>>> )
>>>> )
>>>> )
>>>>
>>>>
>>>> I think the part I'm struggling with most is the Some() wrapped around it.
>>>>
>>>> I'm trying to do:
>>>> jlist.get.asInstanceOf[List[Map[String,String]]].foreach(hotel =>
>>>> println(hotel(name)))
>>>>
>>>> but it's a bit awkward, and worse, doesn't seem to work - I either get
>>>> errors about things not being members of "Any" class, or deprecation
>>>> warnings (on 2.8.0.RC1), or that I need to use Option[List[Any]]
>>>> instead of List[Map[string,string]] but then that fails elsewhere.
>>>>
>>>> Is there a simpler way to handle the Some/Any/Option stuff that
>>>> appears throughout the structure, supposedly?
>>>>
>>>>
>>>> If I was doing this in Perl, the code would be:
>>>> map { say $_->{name} } @places;
>>>> which is rather more succinct.
>>>>
>>>> Cheers,
>>>> Toby
>>>>
>
>
Mon, 2010-05-10, 07:07
#4
Re: Arcane operators (was Re: Traversing data structures)
When you learn the meaning of a function in Scalaz (regardless of it's
name), it applies to a wide variety of types. To elaborate on Tony's
example scalaz.MA#map (or scalaz.MA#∘ ) unifies Option#map,
Traversable#map, Function1#andThen. The extra level of abstraction
makes it a bit harder to choose a suitable name.
Some of these general functions are useful all over the place, and the
frequency of use motivates a short identifier.
-jason
On Mon, May 10, 2010 at 7:44 AM, Toby Corkindale wrote:
> I'm afraid I'm still in the camp of believers in Readable code,
> wherein only simple symbols are used, and methods are named such that
> even someone who doesn't understand the programming language could
> reasonably guess at what is going on.. but perhaps as I come to
> understand more of these arcane symbols, I will change my mind.
Mon, 2010-05-10, 07:17
#5
Re: Arcane operators (was Re: Traversing data structures)
(re-sending to the list because I only replied to the sender, doh)
> Is this a good thing? Just because you can create and overload any
> operators you can imagine, doesn't necessarily mean it's a good idea,
> IMHO.
>
> Sorry, that isn't very constructive, but I was thinking about it a lot
> over the weekend, and wondered what the crowd wisdom on the matter is.
Not that I consider my opinion as wisdom or myself as a very
representative member of the functional community, but anyway... I think
there's high value in good names. Most times, I couldn't care less about
the signature of a function ...err... method. For example, I never had to
look at the API docs of specs (nor at the intellisense suggestions, mind
you), even though I use it extensively. This goes for many well designed
libraries I have encountered.
That being says, the beauty of Scala is that people can go wild with their
ideas. If you find stuff useful you can use it. If you don't, the
operators
aren't global and aren't forced upon your code.
What I'd like to see more is "use-case"-based, example-oriented,
conceptual documentation for that kind of stuff.
Just my 2 cents.
-Andreas
Mon, 2010-05-10, 07:27
#6
Re: Arcane operators (was Re: Traversing data structures)
Here is a fun exercise.
def notTelling[A, B, C](f: A => B, g: B => C): A => C = error("todo")
Complete the above without changing the signature. The rules are:
1) No using bottoms (null, exception)
2) No side-effecting (subverting the type signature)
3) Must terminate
Andreas Flierl wrote:
> (re-sending to the list because I only replied to the sender, doh)
>
>
>> Is this a good thing? Just because you can create and overload any
>> operators you can imagine, doesn't necessarily mean it's a good idea,
>> IMHO.
>>
>> Sorry, that isn't very constructive, but I was thinking about it a lot
>> over the weekend, and wondered what the crowd wisdom on the matter is.
>>
>
> Not that I consider my opinion as wisdom or myself as a very
> representative member of the functional community, but anyway... I think
> there's high value in good names. Most times, I couldn't care less about
> the signature of a function ...err... method. For example, I never had to
> look at the API docs of specs (nor at the intellisense suggestions, mind
> you), even though I use it extensively. This goes for many well designed
> libraries I have encountered.
>
> That being says, the beauty of Scala is that people can go wild with their
> ideas. If you find stuff useful you can use it. If you don't, the
> operators
> aren't global and aren't forced upon your code.
>
> What I'd like to see more is "use-case"-based, example-oriented,
> conceptual documentation for that kind of stuff.
>
> Just my 2 cents.
>
> -Andreas
>
Mon, 2010-05-10, 08:27
#7
Re: Arcane operators (was Re: Traversing data structures)
On Mon, May 10, 2010 at 1:14 AM, Tony Morris <tonymorris@gmail.com> wrote:
Here is a fun exercise.
def notTelling[A, B, C](f: A => B, g: B => C): A => C = error("todo")
Complete the above without changing the signature. The rules are:
1) No using bottoms (null, exception)
2) No side-effecting (subverting the type signature)
3) Must terminate
error("todo") == (A) => g(f(A)) ?
Mon, 2010-05-10, 08:37
#8
Re: Arcane operators (was Re: Traversing data structures)
Jordan Callicoat wrote:
> On Mon, May 10, 2010 at 1:14 AM, Tony Morris wrote:
>
>
>> Here is a fun exercise.
>>
>> def notTelling[A, B, C](f: A => B, g: B => C): A => C = error("todo")
>>
>> Complete the above without changing the signature. The rules are:
>>
>> 1) No using bottoms (null, exception)
>> 2) No side-effecting (subverting the type signature)
>> 3) Must terminate
>>
>>
>>
> error("todo") == (A) => g(f(A)) ?
>
>
That'll do it.
How many correct answers are there?
(I thought this was on the scala-melb mailing list -- didn't intend to
post to scala-user oh well.)
Mon, 2010-05-10, 08:37
#9
Re: Arcane operators (was Re: Traversing data structures)
Jordan Callicoat wrote:
> On Mon, May 10, 2010 at 2:18 AM, Tony Morris wrote:
>
>
>> Jordan Callicoat wrote:
>>
>>> On Mon, May 10, 2010 at 1:14 AM, Tony Morris
>>>
>> wrote:
>>
>>>
>>>> Here is a fun exercise.
>>>>
>>>> def notTelling[A, B, C](f: A => B, g: B => C): A => C = error("todo")
>>>>
>>>> Complete the above without changing the signature. The rules are:
>>>>
>>>> 1) No using bottoms (null, exception)
>>>> 2) No side-effecting (subverting the type signature)
>>>> 3) Must terminate
>>>>
>>>>
>>>>
>>>>
>>> error("todo") == (A) => g(f(A)) ?
>>>
>>>
>>>
>> That'll do it.
>>
>> How many correct answers are there?
>>
>>
>
> If by correct you mean we actually use f and g to compute the return value,
> I think it's the only solution (if we take simple permutations to the
> expression as produced by, e.g., using a 'swap' function, as being
> semantically equivalent).
>
> (I thought this was on the scala-melb mailing list -- didn't intend to
>
>> post to scala-user oh well.)
>>
>>
>
>
Well you have to use only f and g to compute the solution, or you'd be
breaking rule 3.
So there's only one solution given that type and some assumptions then.
Mon, 2010-05-10, 08:47
#10
Re: Arcane operators (was Re: Traversing data structures)
On Mon, May 10, 2010 at 2:18 AM, Tony Morris <tonymorris@gmail.com> wrote:
Jordan Callicoat wrote:
> On Mon, May 10, 2010 at 1:14 AM, Tony Morris <tonymorris@gmail.com> wrote:
>
>
>> Here is a fun exercise.
>>
>> def notTelling[A, B, C](f: A => B, g: B => C): A => C = error("todo")
>>
>> Complete the above without changing the signature. The rules are:
>>
>> 1) No using bottoms (null, exception)
>> 2) No side-effecting (subverting the type signature)
>> 3) Must terminate
>>
>>
>>
> error("todo") == (A) => g(f(A)) ?
>
>
That'll do it.
How many correct answers are there?
If by correct you mean we actually use f and g to compute the return value, I think it's the only solution (if we take simple permutations to the expression as produced by, e.g., using a 'swap' function, as being semantically equivalent).
(I thought this was on the scala-melb mailing list -- didn't intend to
post to scala-user oh well.)
Mon, 2010-05-10, 10:37
#11
Re: Arcane operators (was Re: Traversing data structures)
On 10 May 2010, at 04:00, Ishaaq Chandy wrote:
> Here we go again, this should be an entertaining thread..... :)
By coincidence, I found myself rereading the "Combinator Parsing" chapter of "Programming in Scala" recently, which includes a section entitled "Symbolic versus alphanumeric names" on exactly this subject. Well worth reading if you haven't already done so.
My personal take is there is no right answer to this question. Therefore, my preference is that libraries provide *both* symbolic and alphanumeric versions of functions. As long as there are cross-references from one function to the other in the documentation so that it's clear that they are aliases, this seems to be a cheap way to get the best of both worlds?
--
paul.butcher->msgCount++
Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?
http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: paul@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher
Mon, 2010-05-10, 12:17
#12
Re: Arcane operators (was Re: Traversing data structures)
Paul Butcher wrote:
> On 10 May 2010, at 04:00, Ishaaq Chandy wrote:
>> Here we go again, this should be an entertaining thread..... :)
>
> By coincidence, I found myself rereading the "Combinator Parsing" chapter of "Programming in Scala" recently, which includes a section entitled "Symbolic versus alphanumeric names" on exactly this subject. Well worth reading if you haven't already done so.
>
> My personal take is there is no right answer to this question. Therefore, my preference is that libraries provide *both* symbolic and alphanumeric versions of functions. As long as there are cross-references from one function to the other in the documentation so that it's clear that they are aliases, this seems to be a cheap way to get the best of both worlds?
All agreed.
I'm reminded of an experiment where both chess grandmasters and the
general public were asked to memorise various chess positions: positions
from actual games and positions with randomly placed pieces.
Grandmasters excelled with positions from actual games, but all groups
were equally poor with random positions.
We're all grandmasters at arithmetic notation and pronounceable words,
but most of us are in the general public when it comes to
/: ~< :\ >~ >:> <:<
Alphanumeric aliases for symbolic functions make code much easier to
read aloud and remember.
Mon, 2010-05-10, 14:07
#13
Re: Arcane operators (was Re: Traversing data structures)
Tony Morris wrote:
> So there's only one solution given that type and some assumptions then.
def notTelling[A, B, C](f: A => B, g: B => C): A => C = f.andThen(g)
def notTelling[A, B, C](f: A => B, g: B => C): A => C = a => g(f(a))
While I like the idea of using 'arcane' symbols when it's apropriate I
do find it unconvenient when:
1. it requires unicode to be used. (consoles are not ready for that)
2. when this arcane symbols are completely made up (:\ /:) :) (unless
it's eDSL like parser combinators).
and the third - scala was designed with java interaction in mind. When
there is not 'readable' equivalent - it's almost impossible to use
library outside scala. $u2218 as method name is not an option.
Mon, 2010-05-10, 14:17
#14
Re: Re: Arcane operators (was Re: Traversing data structures)
When I use Class#isAssignableFrom, I have to reach for the
documentation. I never had the same problem with '<:<'
:)
-jason
On Mon, May 10, 2010 at 1:10 PM, Eric Willigers wrote:
> We're all grandmasters at arithmetic notation and pronounceable words, but
> most of us are in the general public when it comes to
> /: ~< :\ >~ >:> <:<
>
> Alphanumeric aliases for symbolic functions make code much easier to read
> aloud and remember.
Mon, 2010-05-10, 14:27
#15
Re: Re: Arcane operators (was Re: Traversing data structures)
On 10 May 2010, at 14:09, Jason Zaugg wrote:
> When I use Class#isAssignableFrom, I have to reach for the
> documentation. I never had the same problem with '<:<'
I'm sure that you're right. But isn't it nice to know that <:< should be pronounced "isAssignableFrom"? And not "lessthancolonlessthan"?
Ishaaq put his finger on the issue when he said that it's one of discoverability - with no additional information, I can make a pretty good guess at what "isAssignableFrom" does. The same does not hold true for "<:<".
--
paul.butcher->msgCount++
Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?
http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: paul@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher
Mon, 2010-05-10, 15:37
#16
Re: Arcane operators (was Re: Traversing data structures)
On Mon, May 10, 2010 at 8:02 AM, Vladimir Kirichenko <vladimir.kirichenko@gmail.com> wrote:
Tony Morris wrote:
> So there's only one solution given that type and some assumptions then.
def notTelling[A, B, C](f: A => B, g: B => C): A => C = f.andThen(g)
def notTelling[A, B, C](f: A => B, g: B => C): A => C = a => g(f(a))
Semantically equivalent. The API reference for andThen says explicitly: "(f andThen g)(x) == g(f(x))". You could theoretically have an unbounded number of permutations, such as:
def lets[A](expr: A) = expr
def be[A,B](f: A => B) = f
def silly[A,B](f: A => B) = f
def notTelling[A, B, C](f: A => B, g: B => C): A => C = a => lets(be(g)(silly(f)(a)))
But it's the same semantic meaning (and same representation when reduced to normal form). So only one correct solution.
While I like the idea of using 'arcane' symbols when it's apropriate I
do find it unconvenient when:
1. it requires unicode to be used. (consoles are not ready for that)
2. when this arcane symbols are completely made up (:\ /:) :) (unless
it's eDSL like parser combinators).
and the third - scala was designed with java interaction in mind. When
there is not 'readable' equivalent - it's almost impossible to use
library outside scala. $u2218 as method name is not an option.
--
Best Regards,
Vladimir Kirichenko
Mon, 2010-05-10, 15:47
#17
Re: Re: Arcane operators (was Re: Traversing data structures)
On Monday May 10 2010, Paul Butcher wrote:
> On 10 May 2010, at 14:09, Jason Zaugg wrote:
> > When I use Class#isAssignableFrom, I have to reach for the
> > documentation. I never had the same problem with '<:<'
>
> I'm sure that you're right. But isn't it nice to know that <:< should
> be pronounced "isAssignableFrom"? And not "lessthancolonlessthan"?
For me, this is the relevant point. If I don't have a pronounceable term
for a symbol, it's a big impediment to me reading anything (code, book,
academic paper, etc.) containing that symbology. Perhaps this is
something that not all people struggle with. Maybe some people read in
a manner that admits visual symbols for which they have no
verbalization without any problem. But for me, a pronounceable name for
a symbol is necessary for smooth reading.
I wonder how this plays out for speakers (literate ones) of languages
whose orthography is not phonetic, such as (traditional) Chinese.
> ...
>
> --
> paul.butcher
Randall Schulz
Mon, 2010-05-10, 16:57
#18
Re: Re: Arcane operators (was Re: Traversing data structures)
On 10 May 2010, at 15:39, Randall R Schulz wrote:
> For me, this is the relevant point. If I don't have a pronounceable term
> for a symbol, it's a big impediment to me reading anything (code, book,
> academic paper, etc.) containing that symbology.
It's not just relevant when you're reading something. What about when you're collaborating with someone (pair programming, for example). Saying (out loud) "we should ensure that x isAssignableFrom y" is much more meaningful than saying "we should ensure that x lessThanColonLessThan y".
--
paul.butcher->msgCount++
Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?
http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: paul@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher
Mon, 2010-05-10, 17:07
#19
Re: Re: Arcane operators (was Re: Traversing data structures)
On Mon, May 10, 2010 at 04:41:59PM +0100, Paul Butcher wrote:
> Saying (out loud) "we should ensure that x isAssignableFrom y" is much
> more meaningful than saying "we should ensure that x
> lessThanColonLessThan y".
...but, parenthetically, much more confusing than "x conformsTo y".
Using passive voice to express a relationship is rarely desirable.
Mon, 2010-05-10, 17:37
#20
Re: Re: Arcane operators (was Re: Traversing data structures)
On Mon, May 10, 2010 at 04:41:59PM +0100, Paul Butcher wrote:
> It's not just relevant when you're reading something. What about
> when you're collaborating with someone (pair programming, for
> example). Saying (out loud) "we should ensure that x
> isAssignableFrom y" is much more meaningful than saying "we should
> ensure that x lessThanColonLessThan y".
Indeed. Hence it is good style to tell how symbols should be
pronounced whenever they are first introduced. Here is a prime
example:
The absence of Contraction and Weakening profoundly changes
the nature of the logical connectives. Implication is now
written A ⊸ B and pronounced `consume A yielding B '. (The
symbol ⊸ on its own is pronounced `lollipop'.) As noted
previously, in the absence of Contraction and Weakening, there
are two distinct ways to formulate conjunction, corresponding
to two distinct connectives in linear logic. These are written
A ⊗ B, pronounced `both A and B ', and A & B , pronounced
`choose from A and B '. (The symbols ⊗ and & are pronounced
`tensor' and `with'.) Disjunction is written A ⊕ B and still
pronounced `either A or B '. Finally, a new form of
proposition is introduced to indicate where Contraction or
Weakening may be used. It is written !A and pronounced `of
course A'. (The symbol ! is pronounced `pling' or `bang!'.)
Philip Wadler, "A Taste of Linear Logic"
But I do agree that pronouncable aliases for symbolic operators are a
good way to formalize this convention in Scala.
Lauri
Mon, 2010-05-10, 22:47
#21
Re: Arcane operators (was Re: Traversing data structures)
As has been said before, the point is that (at least outside of scalaz) one can't take those three for granted.
Also, why is this: ... = { println("Side effect") a => g(f(a))}
called "subverting the type signature"?
On Mon, May 10, 2010 at 2:14 AM, Tony Morris <tonymorris@gmail.com> wrote:
Also, why is this: ... = { println("Side effect") a => g(f(a))}
called "subverting the type signature"?
On Mon, May 10, 2010 at 2:14 AM, Tony Morris <tonymorris@gmail.com> wrote:
Here is a fun exercise.
def notTelling[A, B, C](f: A => B, g: B => C): A => C = error("todo")
Complete the above without changing the signature. The rules are:
1) No using bottoms (null, exception)
2) No side-effecting (subverting the type signature)
3) Must terminate
Andreas Flierl wrote:
> (re-sending to the list because I only replied to the sender, doh)
>
>
>> Is this a good thing? Just because you can create and overload any
>> operators you can imagine, doesn't necessarily mean it's a good idea,
>> IMHO.
>>
>> Sorry, that isn't very constructive, but I was thinking about it a lot
>> over the weekend, and wondered what the crowd wisdom on the matter is.
>>
>
> Not that I consider my opinion as wisdom or myself as a very
> representative member of the functional community, but anyway... I think
> there's high value in good names. Most times, I couldn't care less about
> the signature of a function ...err... method. For example, I never had to
> look at the API docs of specs (nor at the intellisense suggestions, mind
> you), even though I use it extensively. This goes for many well designed
> libraries I have encountered.
>
> That being says, the beauty of Scala is that people can go wild with their
> ideas. If you find stuff useful you can use it. If you don't, the
> operators
> aren't global and aren't forced upon your code.
>
> What I'd like to see more is "use-case"-based, example-oriented,
> conceptual documentation for that kind of stuff.
>
> Just my 2 cents.
>
> -Andreas
>
Mon, 2010-05-10, 23:17
#22
Re: Arcane operators (was Re: Traversing data structures)
2010/5/10 Naftoli Gugenheim :
> Also, why is this:
> ... = {
> println("Side effect")
> a => g(f(a))
> }
> called "subverting the type signature"?
Because you depend on a value (console) that was not passed to you?
Also, if you think of console as being immutable, then you are
returning new console value that is not expressed by return type of
your function.
That's at least is my understanding without referencing to any
sophisticated knowledge.
Mon, 2010-05-10, 23:47
#23
Re: Arcane operators (was Re: Traversing data structures)
On Mon, May 10, 2010 at 5:39 PM, Naftoli Gugenheim <naftoligug@gmail.com> wrote:
There's a sneakier version of this that looks okay, is side-effect-free, and is completely typesafe, yet is also apparently (in category theory) not okay:
= a match {
case 3 => g(2.asInstanceOf[A])
case _ => g(f(a))
}
My impression is that this is a no-no because you aren't allowed to query the type A in any way, and you're also not allowed to assume that for all types that contain the value 3, they also contain the value 2.
--Rex
Also, why is this: ... = { println("Side effect") a => g(f(a))}
called "subverting the type signature"?
There's a sneakier version of this that looks okay, is side-effect-free, and is completely typesafe, yet is also apparently (in category theory) not okay:
= a match {
case 3 => g(2.asInstanceOf[A])
case _ => g(f(a))
}
My impression is that this is a no-no because you aren't allowed to query the type A in any way, and you're also not allowed to assume that for all types that contain the value 3, they also contain the value 2.
--Rex
Tue, 2010-05-11, 00:17
#24
Re: Arcane operators (was Re: Traversing data structures)
This is called type-casing and is not a theorem (and so is not permitted).
Type-casing has this type: forall a b. a -> b or in Scala syntax
def typeCase[A, B](a: A): B = error("uninhabited")
You can demonstrate that this is not a theorem easily with a truth table:
A B (A->B)
0 0 1
0 1 1
1 0 0 // BZZT!
1 1 1
See also Curry-Howard Correspondence.
I once attended a conference (JAOO 2008, Brisbane) where Erik Meijer was
the opening speaker. He demonstrated how it is possible to implemented
this function in Haskell by subverting the type system then proclaimed
"This is a LIE!" in his usual flamboyant accent. I will never forget the
audience reaction.
Rex Kerr wrote:
> On Mon, May 10, 2010 at 5:39 PM, Naftoli Gugenheim wrote:
>
>
>> Also, why is this:
>> ... = {
>> println("Side effect")
>> a => g(f(a))
>> }
>>
>>
>
>
>> called "subverting the type signature"?
>>
>>
>
> There's a sneakier version of this that looks okay, is side-effect-free, and
> is completely typesafe, yet is also apparently (in category theory) not
> okay:
>
> = a match {
> case 3 => g(2.asInstanceOf[A])
> case _ => g(f(a))
> }
>
> My impression is that this is a no-no because you aren't allowed to query
> the type A in any way, and you're also not allowed to assume that for all
> types that contain the value 3, they also contain the value 2.
>
> --Rex
>
>
Wed, 2010-05-12, 03:47
#25
Re: Arcane operators (was Re: Traversing data structures)
On Mon, May 10, 2010 at 7:05 PM, Tony Morris <tonymorris@gmail.com> wrote:
Yeah, I get that part.
But objects in object oriented languages usually add the theorem
forall (a in A) { f(a) => I(A) }
where I(A) is a representation of the set A. So now the type-casing theorem works just fine as long as you can test for equality on I(A):
def upconvert[A,B](a: A,b: B): B = if (f(a)==f(b)) a else b
which is basically what match is/asInstanceOf does.
--Rex
This is called type-casing and is not a theorem (and so is not permitted).
Yeah, I get that part.
But objects in object oriented languages usually add the theorem
forall (a in A) { f(a) => I(A) }
where I(A) is a representation of the set A. So now the type-casing theorem works just fine as long as you can test for equality on I(A):
def upconvert[A,B](a: A,b: B): B = if (f(a)==f(b)) a else b
which is basically what match is/asInstanceOf does.
--Rex
Hi Toby,
Follow The Types.
In my personal opinion, in many of the cases you have given, it is a
*good thing* that the names convey no "apparent meaning", since to do
otherwise is quite a detrimental distraction.
For example, ∘ has this type: (implicit Functor[F]) => F[A] => (A => B)
=> F[B] and satisfies two (unenforced) laws: identity and composition.
*** It's extremely important that no further information is derived in
order to achieve the appropriate abstraction. *** You'll notice the
similarity of signature to the canonical Scala name "map" which is at
least 300% longer than it should be. That's a whopping 300% at a
minimum! No wonder there is so much distraction. In fact, this is so
much a distraction, that languages such as DDC/Haskell make this
function *implicit* such that the name length is zero (i.e. lifting is
"automatic").
Did you know that scala.Function1 has a map function, except it has this
name: "andThen." Take a look at the signature:
Function1[T, A] => (A => B) => Function1[T, B]
Notice the similarity to (for example List.map):
List[A] => (A => B) => List[B]
Or perhaps:
Option[A] => (A => B) => Option[B]
Thought provoking?
In any case, this issue of function names is contentious and one that is
difficult to overcome, especially on the Scala mailing lists (see
history). Perhaps I can refer you to my young colleague who sits next to
me, who once strongly believed in the value of function names, but I
have brainwashed (disciplined) him to the contrary to some extent! haha!
Just joking. In all honesty, I'm in a bind in how to present this
position in a constructive way, since such efforts often ends in
bitterness and miscommunication. I must tread lightly, but I am
otherwise happy to help and I hope this email does in some way.
Toby Corkindale wrote:
> On 7 May 2010 12:26, Tony Morris wrote:
>
>> See scalaz.Traverse or the paper titled, The Essence of the Iterator
>> Pattern.
>>
>
> The paper was interesting, thanks.
> I had a look, but scalaz.Traverse seems to suffer from the same lack
> of documentation as the rest of the library.
> I tried reading the source for the Traverse class, but it's full of
> arcane operators that I don't understand:
> ie. "#::", "∘" & "↦".
>
> Which reminds me - I was looking at the source for another
> undocumented library, and it seemed to be all about using a dozen
> different odd operators, such as "/:", ">:>" and ">~". (For a few, see
> http://databinder.net/dispatch-doc/dispatch/Handlers.html)
> I am getting a little worried that Scala is turning into APL or Perl4,
> and looking more like line noise than code.
>
> Is this a good thing? Just because you can create and overload any
> operators you can imagine, doesn't necessarily mean it's a good idea,
> IMHO.
>
> Sorry, that isn't very constructive, but I was thinking about it a lot
> over the weekend, and wondered what the crowd wisdom on the matter is.
>
> -Toby
>
>
>
>> Toby Corkindale wrote:
>>
>>> Hi,
>>> I seem to be having to make a lot of effort to traverse some simple
>>> data structures, and so wondered if I could ask the crowd for their
>>> wisdom.
>>>
>>> Let's say I have a data structure like this: (as returned by the json
>>> parser in scala)
>>>
>>> Some(
>>> List(
>>> Map(
>>> name -> "The Salisbury",
>>> url -> "http://example.com/1"
>>> ),
>>> Map(
>>> name -> "The Foundry",
>>> url -> "http://example.com/2"
>>> )
>>> )
>>> )
>>>
>>>
>>> I think the part I'm struggling with most is the Some() wrapped around it.
>>>
>>> I'm trying to do:
>>> jlist.get.asInstanceOf[List[Map[String,String]]].foreach(hotel =>
>>> println(hotel(name)))
>>>
>>> but it's a bit awkward, and worse, doesn't seem to work - I either get
>>> errors about things not being members of "Any" class, or deprecation
>>> warnings (on 2.8.0.RC1), or that I need to use Option[List[Any]]
>>> instead of List[Map[string,string]] but then that fails elsewhere.
>>>
>>> Is there a simpler way to handle the Some/Any/Option stuff that
>>> appears throughout the structure, supposedly?
>>>
>>>
>>> If I was doing this in Perl, the code would be:
>>> map { say $_->{name} } @places;
>>> which is rather more succinct.
>>>
>>> Cheers,
>>> Toby
>>>