Arc Forumnew | comments | leaders | submitlogin
2 points by Pauan 4159 days ago | link | parent

Okay. I've spent a bit of time mulling this over and trying out some stuff. Here's what I came up with.

How about a language that's like Haskell/Shen: currying everywhere. This language would be based heavily on functions, of course, which are expressed with "->" as follows:

  foo %x -> %x + 2
The above is equivalent to this in Arc:

  (def foo (x) (+ x 2))
Now, how this works is... everything to the left of the "->" is a pattern. Everything to the right is the function's body. If a variable starts with % it's local to the function, if not, it's global.

As a quick test of this system, I went through some semi-contrived examples taken from http://en.wikipedia.org/wiki/Duck_typing

  class Duck:
    def quack(self):
      print("Quack")
    def fly(self):
      print("Flap, Flap")
   
  class Person:
    def __init__(self, name):
      self.name = name
    def quack(self):
      print("{} walks in the forest and imitates ducks to draw them".format(self.name))
    def fly(self):
      print("{} takes an airplane".format(self.name))
   
  def quack_and_fly(duck):
    duck.quack()
    duck.fly()
   
  quack_and_fly(Duck())
  quack_and_fly(Person("Jules Verne"))
And here it is in this hypothetical currying-pattern-matching language:

  duck ->
    [ quack -> prn "Quack"
      fly   -> prn "Flap, Flap" ]

  person %n ->
    [ quack -> prn "@%n walks in the forest and imitates ducks to draw them"
      fly   -> prn "@%n takes an airplane" ]

  quack-and-fly [ quack %q fly %f ] -> %q; %f

  quack-and-fly duck
  quack-and-fly person "Jules Verne"
Wooow that is short! It also means that (except for % variables which are local) the pattern matching to the left of -> matches the function call.

If you wanted to, you could use parens like Shen instead of no-parens like Haskell.

Some downsides? Well, since it's using currying, there could be some issues with that. In particular, variable argument functions wouldn't be possible. There's also potentially some scoping issues and such.

Overall though, I think this idea is cool enough to actually try and implement it in a simple interpreter, to figure out all the kinks.



1 point by Pauan 4158 days ago | link

Okay, I was able to solve a couple problems with my object pattern-matching...

  [ foo = 5 | bar = 10 ]
The above is a collection of patterns. Specifically, it has a "foo" pattern that maps to 5, and a "bar" pattern that maps to 10. Now, let's put this object into a variable:

  pattern = [ foo = 5 | bar = 10 ]
Now how do we extract the subpatterns? Like so:

  pattern [ foo ]
  pattern [ bar ]
The above returns 5, and then 10. And we can extract multiple patterns at once:

  pattern [ foo | bar ]
The above returns 10. This largely removes the need for "as" patterns, which is something I found cumbersome to use. You can think of | as being kinda like "do". It will first call the foo pattern, then the bar pattern.

Also, in Haskell you might write this:

  fib 0 = 0
  fib 1 = 1
  fib n = fib (n-1) + fib (n-2)
In this language you might write this:

  [ fib  0 = 0
  | fib  1 = 1
  | fib %n = fib (%n - 1) + fib (%n - 2) ]
Hmm... I'm still working out the kinks in the object system...

-----

1 point by Pauan 4158 days ago | link

Okay, even more thinking... what if all objects in this system were simply a collection of functions? Then you'd write something like this:

  duck =
    quack = prn "Quack"
    fly   = prn "Flap, Flap"

  person %n =
    quack = prn "@%n walks in the forest and imitates ducks to draw them"
    fly   = prn "@%n takes an airplane"

  quack-and-fly %x = %x quack; %x fly

  quack-and-fly: duck
  quack-and-fly: person "Jules Verne"
Wow! Even shorter! This reminds me of CoffeeScript's implicit objects: http://coffeescript.org/#objects_and_arrays

-----

1 point by Pauan 4159 days ago | link

For comparison, here it is with some parens:

  (duck) ->
    [ quack -> (prn "Quack")
      fly   -> (prn "Flap, Flap") ]

  (person %n) ->
    [ quack -> (prn "@%n walks in the forest and imitates ducks to draw them")
      fly   -> (prn "@%n takes an airplane") ]

  (quack-and-fly [ quack %q fly %f ]) -> (%q); (%f)

  (quack-and-fly (duck))
  (quack-and-fly (person "Jules Verne"))
I wasn't sure whether "quack" and "fly" should be in parens or not...

-----

1 point by Pauan 4159 days ago | link

Like Haskell, it may be better to use =

  duck =
    [ quack = (prn "Quack")
      fly   = (prn "Flap, Flap") ]

  person %n =
    [ quack = (prn "@%n walks in the forest and imitates ducks to draw them")
      fly   = (prn "@%n takes an airplane") ]

  quack-and-fly [ quack %q fly %f ] = %q; %f

  quack-and-fly duck
  quack-and-fly person "Jules Verne"
Oh my, am I going to invent a dynamically typed Haskell with immutable objects? I guess next will be laziness and monads...

-----

1 point by akkartik 4159 days ago | link

  quack-and-fly person "Jules Verne"
Haskell would keep it from conflicting with currying:

  quack-and-fly (person "Jules Verne")
Did you have some other way to avoid the conflict?

-----

1 point by Pauan 4158 days ago | link

"Did you have some other way to avoid the conflict?"

No, that's a reasonable way to solve it. But I still would like optional args, variable args, and vaus. Wheee a dynamic Haskell with vaus~

Hmm... with a little syntax, you could write this:

  quack-and-fly: person "Jules Verne"
That's like the . operator in Haskell.

-----