Hello ChucKers, Good idea on having the documentation sprint -- it has sparked my interest in ChucK again. Given the time of year I thought I'd throw out my wish list for new ChucK features/enhancements: 1. Import/include mechanism with namespaces The import.ck mechanism in LiCK works ok, but is hard to maintain. All dependencies between classes have to be calculated manually so that all the Machine.adds are in the right order. Having 136 or however many it is classes in LiCK all in the same namespace (no namespace, or the "default package", that is) is a mess. 2. Java-style interface abstract classes, or multiple class inheritance I need either class Foo {} interface Bar {} interface Baz {} class Qux extends Foo implements Bar, Baz or class Foo {} class Bar {} class Baz {} class Qux extends Foo, Bar, Baz 3. Tool for generating ChucK class documentation from its source code (similar to doxygen or javadoc) 4. A way to soft-kill a shred when in an on-the-fly programming session By soft-kill, I mean kill the shread when it is no longer producing non-zero samples, not just kill it immediately. Using e.g. $ chuck - 1 is not pleasant when that shred is still producing sound. 5. Class/type introspection 6. Closures or function pointers 7. Constructors michael
On Fri, Jan 1, 2010 at 11:15 PM, Michael Heuer
2. Java-style interface abstract classes, or multiple class inheritance Or maybe Objective-C style protocols?
These work sorta like this:
(void) foo (int)bar:
If we're serious about changing the ChucK language, I'd put in my vote for a Ruby-style approach. I've come to appreciate Ruby's expressive power derived from -- among many other things -- duck typing and modules / mixins. And a few dozen other features, shamelessly stolen from other languages. - r
Rob;
If we're serious about changing the ChucK language, I'd put in my vote for a Ruby-style approach.
Personally I'm more interested in looking what issues those other languages solve, how those related to our concerns, then finally figuring out how to solve those things in a ChucKist way. If you are really interested in mixing ChucK and Ruby you may want to look at what's on Tom's cocktail menu; http://github.com/alltom/ruck Yours, Kas.
On 3 Jan 2010, at 16:47, Kassen wrote:
If we're serious about changing the ChucK language, I'd put in my vote for a Ruby-style approach.
Personally I'm more interested in looking what issues those other languages solve, how those related to our concerns, then finally figuring out how to solve those things in a ChucKist way.
I think so, too. All computer languages have quirks, or "gotchas" as they are called here: http://en.wikipedia.org/wiki/Gotcha_(programming) In addition, languages tend to be well designed for a certain type of issues, and using them in other circumstances can be rather cumbersome.
If you are really interested in mixing ChucK and Ruby you may want to look at what's on Tom's cocktail menu; http://github.com/alltom/ruck
This link describes some peculiarities of Ruby, of which some are not so good: http://en.wikipedia.org/wiki/Ruby_(programming_language)#Deviations_from_beh... For example, imposing extra conditions on identifiers is not good - I use Haskell, in which variables can only start with lower case (those that start with uppercase are reserved fro types), and when one accidentally is doing wrong, one gets mysterious compiler errors. A declarative language, I think is best, which is essentially what is used in math - the road that ChucK is on. Another problem of languages is having too few precedence levels - some investigated math, and found that there are a lot more than in typical computer languages. Here, Ruby inherits the problem of Pascal for logical operators. A language benefits readability if one can eliminate the need of parenthesizes. Also, Ruby treats a line ending as an end of statement, which generally is bad if one needs to write something that takes up more than one line. This idea comes from scripting languages, like shell, which are good for writing simple things, but known to be problematic for outright programs (steeps learning curve, and hard to read and debug). Haskell uses an alternative called layout syntax: in addition to normal bracketing to environments one can drop them and use indentation instead. For example, -- Leading term in monomial order. lead :: Polynomial -> Term lead p = last xs where Xs xs = normalize p Here, the indentation of "where" says that the stuff that follows on the same indentation level belongs to the block. The problem is that the compiler tends to give strange error messages "possibly due to wrong layout" and one may have to guess if it is a layout problem or not. (Also, it sets a tab equal to 8 spaces when computing layouts, which has fallen out of use.) Haskell has the problem that the function name must be repeated often when defining a new function. Another quirk is the lazy evaluation, which is wholly incompatible with imperative structures, which leads to the introduction of the complicated concept of monads (an import from math category theory). Getting back to Ruby, it treats various objects as Boolean, which is a bad idea, inviting errors. The gotcha link mentions the classical C mistake, confusing the two if (a = b) then ... if (a == b) then ... The first is an assignment, and the second a test of equality - it is common to do mistakes on this one. But the problem could have largely been circumvented if types did not implicitly convert to Boolean types. Then the first one would have generated a compiler error, except when programming specifically Boolean types, but that does not happen so often. In general, it is a bad to have implicit type conversions to types which loose information. That is a C-quirk. Anyway, just examples on what one might have to think about when moving along. If people try out what works and not works and discusses it here, that may give the developers feedback. Hans
Hey all, I'm going to get on a soapbox here. Sorry in advance for sounding like a hot air bag. <soapbox> It's hard to change the C-like nature of Chuck from the grammar side. And there are a lot of reasons not to attempt to change the grammar. Speed, ease of learning, etc. Now, some attempts have been made to bring a higher-level of programming to Chuck, most notably in Michael Heuer's LiCK library, which I encourage everyone to take a look at. http://github.com/heuermh/lick You have Lists here, ArrayLists, functors, which allow for a verbose kind of functional programming, etc. It's hard to approach at the moment, but if you use it, you might forget you're programming Chuck. I think it's important to stay within the confines that our dev's have set out for Chuck. I think it's important to keep Chuck lean, fast, and easy to learn (i.e. C-like). But it's also important for Chuck to allow the kind of thing that Michael's trying to build--because it's more like Ruby, Python, the nice parts of Java 6, Haskell, etc. -- all those things we want out of a good scripting language. Points: It would be great if it was easier to approach LiCK (and other libraries). Only documentation can help that. There is none. It's hard to make. Therefore, we need a system to generate documentation. It would be great if LiCK (and other libraries) were easier to use. We need to be able to import them. Chuck needs a proper preprocessor, an import system, something. Graham Coleman wrote a Chuck preprocessor/shell in Perl, which I've used in the past. It's really a nice thing to have. It would be great is LiCK could be be less verbose. There's no reason that functions shouldn't be objects by default. There ought to be a function type. Then we wouldn't need functors to do functional programming. Perhaps even a lambda keyword. "fun int" could define a type... lambda(int y) { return y + 1; } @=> fun int x; <<< x(4) >>>; // prints 5 // obviously, that's fraught with issues... function pointers could work like this: fun int f(int g) { return g+1; } f @=> function x; <<< x(4) >>>; // prints 5 <<< x(4.4) >>>; // error This is going to be a huge thing to implement. First, we should be able to continue to better do these things using the built-in object system using functors. Okay, but we need to be able to determine the class of an object at runtime (I've experimented with this already--so has Graham Coleman, who had a patch for an instanceOf method). This requires introspection. We should have that. Constructors -- we've been flirting with that idea for a long time. We need those. Interfaces... yes. These things would really allow us to create easy to use libraries for chuck IN CHUCK that allow for multiple paradigms (functional, OO, imperative, etc). We can make Chuck feel like Ruby. We can make Chuck feel like LISP. We can make Chuck feel like Java, or C++, or whatever. But only when we have these things. </soapbox> Just some ideas. Mike
On 3 Jan 2010, at 23:39, mike clemow wrote:
There's no reason that functions shouldn't be objects by default. There ought to be a function type. Then we wouldn't need functors to do functional programming. Perhaps even a lambda keyword. "fun int" could define a type...
lambda(int y) { return y + 1; } @=> fun int x;
<<< x(4) >>>; // prints 5
// obviously, that's fraught with issues... function pointers could work like this:
fun int f(int g) { return g+1; }
f @=> function x;
<<< x(4) >>>; // prints 5 <<< x(4.4) >>>; // error
ChucK, with its "fun" has in fact a syntax similar to SML (and OCaml is a derivation). In SML, one writes fun twice x = x*2 val twice = fn : int -> int The typing is a bit cumbersome - more like the old style in C, which has fallen largely out of use. In Haskell, the definition is twice :: Int -> Int twice x = x*x This is better, but one ends up with repeating the name of the function. Here, it repeated once, but one can have cases: f :: Int -> Int f 1 = ... f 2 = ... where the 1 and 2 can be various complicated patterns. The type must also start with uppercase names. In Haskell, the lambda is written as \x -> x*x if I would want to define the function on the fly without giving it a name. This is better, closer to that math x |-> x*x, on which Church's original lambda-calculus was based on. So an alternative way to define function is twice :: Int -> Int twice = \x -> x*x In fact, one can omit the type declaration, because Haskell uses a Hindley-Milner like type system which mostly can infer the type from an expression. This is convenient, but imposes limitations on function name overloading.
This is going to be a huge thing to implement.
Functional lambda calculus takes a bit to implement. But doing C++ style templates is not a very happy solution, that either. :-)
First, we should be able to continue to better do these things using the built-in object system using functors. Okay, but we need to be able to determine the class of an object at runtime (I've experimented with this already--so has Graham Coleman, who had a patch for an instanceOf method). This requires introspection. We should have that.
Constructors -- we've been flirting with that idea for a long time. We need those. Interfaces... yes.
These are much more modest additions, and it would be nice to see them. Hans
These are much more modest additions, and it would be nice to see them.
I wonder how close we could get to Lambda calculus by allowing for overloading the ChucK operator from within the language? I want that. The ChucK operator is clearly "ChucKian" and I feel it has proven to be very expressive. Aside from that I think that the suggestions and notes here are really interesting and I'm learning a lot from them but I think it would be short-changing ourselves to have this debate solely in CS terms. CS to me (no offence to the CS professors here) is a tool and the end result will have to be music/sound/etc. The tools will have to make practical sense in reasoning about music and sound. It might be easier to talk about these things using muck-up example code that would do some musical thing. In the end we would like to express feelings (or learn about sound, or get our feet wet in code...) and while CS papers might be a stage in getting there they aren't so great as a end result. Personally I would have made Ge fail if his thesis (which really is quite interesting) wasn't backed by people the world over actually using this stuff and enjoying themselves. I don't mean to critique the proposals above saying this, I just wanted to make some suggestions on what to judge such proposals on and provide a perspective on how we might make them in the most efficient way. Yours, Kas.
On 4 Jan 2010, at 14:58, Kassen wrote:
These are much more modest additions, and it would be nice to see them.
I wonder how close we could get to Lambda calculus by allowing for overloading the ChucK operator from within the language? I want that. The ChucK operator is clearly "ChucKian" and I feel it has proven to be very expressive.
In Haskell, it is (examples below) really the Hindley-Milner type system that imposes limitations on function name. Similar to the unification in of Prolog clause heads, it requires two expressions to be unifiable. In more diverse system, as math, this is not true. And if one would want to keep the C++ style name overloading that Chuck, one must find ways to localize names. To be more explicit by these problems, Haskell has a class class (Eq a, Show a) => Num a where (+), (-), (*) :: a -> a -> a negate :: a -> a abs, signum :: a -> a fromInteger :: Integer -> a fromInt :: Int -> a -- Minimal complete definition: All, except negate or (-) x - y = x + negate y fromInt = fromIntegral negate x = 0 - x As you can see, this class has arithmetic operators (+), (-), and (*) in it, plus some sporadic functions fromInteger (conversion from multiprecision integers), fromInt (conversion from int). Now, the limitation is that in order to name load these operators, one has to define a data type and make an instance of the whole class. So you can't just define a monoid which overloads just (*). It blocks all uses of the symbol (*) outside this class. It has to do with the polymorphy of these operators: (+), (-), (*) :: a -> a -> a The "a" can be substituted with any other type, which may itself be polymorphic. The class tries to ensure that the behavior of these operators are consistent over all types. (Haskell does however admit partially defined classes, so one can skip some definitions. But it is still ain't convenient.) So, for example, it is not possible to define a data type "Vector a" that contains a lists of elements from a data and then define scalar multiplications (*) :: a -> Vector a -> Vector a because (*) must be of type a -> a -> a and defined via the class Num. So this is something that is a problem when trying to do C++ style name overloading. There is a Haskell project of a "Numerical Prelude" that should refine the original Prelude so that such things should be possible, but it seems stalled for years now. And attempts to generalize seem getting stuck on essentially extending the type system with elements from mathematical logic. This can't be done easily, because this type unification feature simply isn't true in general math or even programming. So even though this polymorphic type system is nice in some respects, it also prevents one from doing the operator overloading one might want to have.
Aside from that I think that the suggestions and notes here are really interesting and I'm learning a lot from them but I think it would be short-changing ourselves to have this debate solely in CS terms. CS to me (no offence to the CS professors here) is a tool and the end result will have to be music/sound/etc. The tools will have to make practical sense in reasoning about music and sound.
It might be easier to talk about these things using muck-up example code that would do some musical thing. In the end we would like to express feelings (or learn about sound, or get our feet wet in code...) and while CS papers might be a stage in getting there they aren't so great as a end result. Personally I would have made Ge fail if his thesis (which really is quite interesting) wasn't backed by people the world over actually using this stuff and enjoying themselves.
I don't mean to critique the proposals above saying this, I just wanted to make some suggestions on what to judge such proposals on and provide a perspective on how we might make them in the most efficient way.
This is in fact an important aspect of language design: a language tends to be better if the developers are using them. Languages designed for others to use (like Cobol I think was mentioned) tend to be rather awful. I think Haskell has a very nice syntax. Perhaps it can influence if ChucK gets functional. But ChucK must find its own way. Hans
On Sat, Jan 2, 2010 at 2:15 AM, Michael Heuer
Good idea on having the documentation sprint -- it has sparked my interest in ChucK again. Given the time of year I thought I'd throw out my wish list for new ChucK features/enhancements:
I had a new year wishlist. I'm working on it now: http://ckvlang.org/ Looking for help! :D -- Tom Lieber http://AllTom.com/
great idea! i love chuck but i like lua more as a language. downloading... best joerg On 04.01.10 00:10, Tom Lieber wrote:
On Sat, Jan 2, 2010 at 2:15 AM, Michael Heuer
wrote: Good idea on having the documentation sprint -- it has sparked my interest in ChucK again. Given the time of year I thought I'd throw out my wish list for new ChucK features/enhancements:
I had a new year wishlist. I'm working on it now:
Looking for help! :D
-- http://joerg.piringer.net http://www.iftaf.org http://www.vegetableorchestra.org
On 4 Jan 2010, at 01:15, joerg piringer wrote:
great idea! i love chuck but i like lua more as a language.
Haskell has a much more concise syntax, it seems. The Fibonacci table here http://en.wikipedia.org/wiki/Lua_(programming_language)#Example_code can in Haskell be computed using a recursively defined list: fib = [0,1] ++ [fib!!(i-1) + fib!!(i-2)| i <- [2..]] Haskell supports infinite lists, like [2..] whose values are lazily computed (at need, caching intermediate results). So the potentially infinite fib table above is computed to the point it is needed. Hans
Michael Heuer wrote:
Given the time of year I thought I'd throw out my wish list for new ChucK features/enhancements:
I know I'm pretty alone one this but my wish-list is short: 0. More efficient WM. I'm at the edge of what can be done with my 2.4Ghz dual core laptop, and unfortunately have to look for non-chuckian solutions :-( -- Atte http://atte.dk http://modlys.dk
Hey Atte,
You are on linux, right? Have you tried wmii? It is super efficient,
both cpu wise and workflow wise, and it is a lot of fun to use. It is
perfect for chucking too. I use it on my EEEPC with chuck and alsa and
a very stark debian lenny install.
--art
On Tue, Jan 5, 2010 at 1:41 PM, Atte André Jensen
Michael Heuer wrote:
Given the time of year I thought I'd throw out my wish list for new ChucK features/enhancements:
I know I'm pretty alone one this but my wish-list is short:
0. More efficient WM. I'm at the edge of what can be done with my 2.4Ghz dual core laptop, and unfortunately have to look for non-chuckian solutions :-(
-- Atte
http://atte.dk http://modlys.dk _______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
Adam; You are on linux, right? Have you tried wmii? It is super efficient,
both cpu wise and workflow wise, and it is a lot of fun to use. It is perfect for chucking too. I use it on my EEEPC with chuck and alsa and a very stark debian lenny install.
At Tom's recommendation I started playing with WDM, which I'm liking a lot so far, aside from having issues with Alsa. I can't get my Alsa ChucK to output sound using it so far; somehow the soundcard seems unavailable. Any ideas on where to start solving that? I have no such issues with Gnome. Yours, Kas.
Adam Tindale wrote:
Hey Atte,
You are on linux, right? Have you tried wmii?
Hmmm. By WM I meant VM (as in chuck Virtual Machine), sorry for that confusing typo. And regarding WM (Window manager) I used to chuck in tty, with X killed, but recently it seems that I cannot get more performance (ok maybe <5% at the most) that way. So now I'm usually sticking to gnome with bells/whistles. -- Atte http://atte.dk http://modlys.dk
Atte; And regarding WM (Window manager) I used to chuck in tty, with X killed, but
recently it seems that I cannot get more performance (ok maybe <5% at the most) that way. So now I'm usually sticking to gnome with bells/whistles.
That's roughly what I found too. The bells&whistles run -mostly- on the GPU anyway. I think it will only matter at extremely low buffer settings where the occasional usage spike of non-ChucK processes may cause a glitch. We need the context-sensitive block processing as it's our lack of block processing that is the main reason ChucK takes a comparatively large amount of cpu. The context-sensitive version (as in; no block processing for parts of the UGen graph that have feedback) sounds like a very good idea, I think it should be possible, in a way it even seems obvious. The one issue is that I don;t think anyone else has ever done that. That one should be a big leap in performance, after that we may have to think about multi-core support. Strongly typed multi-core support sounds distinctly non-trivial to me. I think Ge was looking into it but the problem is notoriously hard and we are smack in the middle of the kind of area where it's especially hard, for what I understand of it. Yours, Kas.
What about this:
normal function def -
fun int addOne(int x)
{
return x+1;
}
I think that what would make a functional paradigm possible is that "fun
<type>" is a type definition. The goal is something like -
fun void run(fun void f)
{
f();
}
this is weird, but valid...
fun fun void combine( fun void f, fun void g )
{
fun void h()
{
f();
g();
}
return h;
}
we could do anonymous functions in a way that SClang does, using just curly
braces -
{
int x, y;
return x + y;
}
then we can overload the @=> operator to allow (with added keyword "arg" to
define arguments) -
{
arg int x, y;
return x + y;
} @=> fun int f;
<<< f(4, 5) >>>; // prints "9"
and then we can add (i'm just ranting now) default/optional arguments from
Python -
fun int f(int x=5, int y=9)
{
return x+y;
}
<<< f(1,2) >>>; // prints "3"
<<< f() >>>; // prints "14"
<<< f(6) >>>; // prints "15", I guess...
imaginary syntax is fun (void).
-Mike
2010/1/6 Kassen
Atte;
And regarding WM (Window manager) I used to chuck in tty, with X killed,
but recently it seems that I cannot get more performance (ok maybe <5% at the most) that way. So now I'm usually sticking to gnome with bells/whistles.
That's roughly what I found too. The bells&whistles run -mostly- on the GPU anyway. I think it will only matter at extremely low buffer settings where the occasional usage spike of non-ChucK processes may cause a glitch.
We need the context-sensitive block processing as it's our lack of block processing that is the main reason ChucK takes a comparatively large amount of cpu. The context-sensitive version (as in; no block processing for parts of the UGen graph that have feedback) sounds like a very good idea, I think it should be possible, in a way it even seems obvious. The one issue is that I don;t think anyone else has ever done that.
That one should be a big leap in performance, after that we may have to think about multi-core support. Strongly typed multi-core support sounds distinctly non-trivial to me. I think Ge was looking into it but the problem is notoriously hard and we are smack in the middle of the kind of area where it's especially hard, for what I understand of it.
Yours, Kas.
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
Mike; What about this:
Well; fun int foo( int arg) { return 3; } fun void bar( int arg) { <<<"boring">>>; } //overload fun void bar ( fun arg) { <<<"fun">>>; } 1 => foo => bar; Would that print "fun" or "boring"? That last line is a case where we refer to the function without parentheses yet still expect it to be called and to return under current syntax. Yours, Kas.
On 6 Jan 2010, at 18:30, Kassen wrote:
fun int foo( int arg) { return 3; }
fun void bar( int arg) { <<<"boring">>>; }
//overload fun void bar ( fun arg) { <<<"fun">>>; }
1 => foo => bar;
Would that print "fun" or "boring"? That last line is a case where we refer to the function without parentheses yet still expect it to be called and to return under current syntax.
In C++, thinking about the output stream operator >>, this is resolved by defining how this operator binds. This enables writing stream manipulators, not possible in ChucK, as it does not seem to have any such rules. So if the last line binds as (1 => foo) => bar; then the inner parenthesis returns an int, and then it must be the first bar. To get the other one, one must write explicitly 1 => (foo => bar); Treating functions as data is of course possible in C/C++, only that they are static there: can only happen at compile time. ChucK is interpreted, so all already happens at runtime. Perhaps that makes it easier to implement the stuff. The other question is what kind of polymorphy one wants to have. In C/C ++, one would have to specify the type of the function: fun void bar(fun int f(int)) so that the actions operated on f can be checked - if one would not want to be able to pass a string onto f, and the compiler should check that, this is necessary. But one wants polymorphy when implementing more general things, like say a sorting algorithm that should be applicable over a range of types. One would then want the computer to check that the data type has defined a comparison operator necessary for the sorting. (In C, one can do this by essentially type-less function pointers.) C++ tries to amend this by a complicated template system. Haskell uses a Hindley-Milner-like type system, whose main property is that the polymorphic type of an expression can be computed (by unification of the components). For example, in Hugs, I can compute the type using ":t", if first define a function without a type as f (x:xs) = x and the in HUgs interactively :t f f :: [a] -> a It is nice, but imposes huge restriction on the function name overloading. Hans
Kas,
1 => foo;
this is sane, but this isn't:
1 => foo => bar;
foo(1) is the same as 1 => foo
foo => bar is the same as bar(foo)
however, I was suggesting that I could assign the object/function foo to
reference bar this way:
foo @=> bar;
which means this:
1 => bar;
would now return 3 because bar is now a reference to the same function foo
is a reference to.
see what I mean?
additionally, given
fun fun int bing(int b)
{
fun void funk(int i) { return b+i; }
return funk;
}
this:
<<< 4 => bing(5) >>>;
should print "9" in my weird world. I'm not sure that this actually is
going to work this way, i'm just suggesting that we could get a lot of
interesting things if functions were objects. I might be lynched for saying
this, but JavaScript works this way. It's a lot easier with a dynamically
typed language in which variables are always just references to other things
(like they are in Chuck with objects, but not with primitives).
I don't think we're going to get away with this without adding some sort of
keyword to Chuck. "function" is already taken as a keyword, according to
the documentation, even though nothing using it has been implemented as far
as I know. Perhaps we can add a function type that extends object.
-Mike
2010/1/6 Kassen
Mike;
What about this:
Well;
fun int foo( int arg) { return 3; }
fun void bar( int arg) { <<<"boring">>>; }
//overload fun void bar ( fun arg) { <<<"fun">>>; }
1 => foo => bar;
Would that print "fun" or "boring"? That last line is a case where we refer to the function without parentheses yet still expect it to be called and to return under current syntax.
Yours, Kas.
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
oops, the definition should have been this:
fun fun int bing(int b)
{
fun int funk(int i) { return b+i; }
return funk;
}
mike
On Sun, Jan 10, 2010 at 1:59 PM, mike clemow
Kas,
1 => foo;
this is sane, but this isn't:
1 => foo => bar;
foo(1) is the same as 1 => foo
foo => bar is the same as bar(foo)
however, I was suggesting that I could assign the object/function foo to reference bar this way:
foo @=> bar;
which means this:
1 => bar;
would now return 3 because bar is now a reference to the same function foo is a reference to.
see what I mean?
additionally, given
fun fun int bing(int b) { fun void funk(int i) { return b+i; } return funk; }
this:
<<< 4 => bing(5) >>>;
should print "9" in my weird world. I'm not sure that this actually is going to work this way, i'm just suggesting that we could get a lot of interesting things if functions were objects. I might be lynched for saying this, but JavaScript works this way. It's a lot easier with a dynamically typed language in which variables are always just references to other things (like they are in Chuck with objects, but not with primitives).
I don't think we're going to get away with this without adding some sort of keyword to Chuck. "function" is already taken as a keyword, according to the documentation, even though nothing using it has been implemented as far as I know. Perhaps we can add a function type that extends object.
-Mike
2010/1/6 Kassen
Mike;
What about this:
Well;
fun int foo( int arg) { return 3; }
fun void bar( int arg) { <<<"boring">>>; }
//overload fun void bar ( fun arg) { <<<"fun">>>; }
1 => foo => bar;
Would that print "fun" or "boring"? That last line is a case where we refer to the function without parentheses yet still expect it to be called and to return under current syntax.
Yours, Kas.
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
On 10 Jan 2010, at 20:00, mike clemow wrote:
additionally, given
fun fun int bing(int b) { fun int funk(int i) { return b+i; } return funk; } this:
<<< 4 => bing(5) >>>;
should print "9" in my weird world.
You are sort of reinventing the wheel, or at least (Standard) ML, here. See http://en.wikipedia.org/wiki/Standard_ML http://en.wikipedia.org/wiki/ML_(programming_language) You want to make an anonymous function, and this is where the lambda comes into play. In Haskell (in SML, I think just replace \ with fn and -> with =>), this would be bing :: Num a => a -> a -> a bing b = \i -> b + i and bing(5)(4) evaluates to 9; bing is simply a functional: returns a function. Then bing 5 is simply a function, here is the type: bing 5 :: Num a => a -> a In Haskell, the original function definition can be written without the type declaration, relying on the Hindley-Milner type system. But this convenience, as globally present in Haskell looses out on function name overloading. Hans
Hi,
On Sun, Jan 10, 2010 at 4:16 PM, Hans Aberg
... You are sort of reinventing the wheel, or at least (Standard) ML, here. See http://en.wikipedia.org/wiki/Standard_ML http://en.wikipedia.org/wiki/ML_(programming_language)http://en.wikipedia.org/wiki/ML_%28programming_language%29
We're not reinventing the wheel so much as exploring how certain features might be added to the Chuck language--features that appear in many other languages (JavaScript, Haskell, Python, and ML too). I mean, LISP did this stuff before any of the others... I think it's great to look at the way other languages do things as examples, but we're not about to re-make the Chuck system using Haskell syntax or LISP, or ML. It's highly likely that Chuck will get new features, but the ones it gets will be the ones that seem most important to the devs and the community, I suppose. Mike
On 10 Jan 2010, at 22:38, mike clemow wrote:
You are sort of reinventing the wheel, or at least (Standard) ML, here. See http://en.wikipedia.org/wiki/Standard_ML http://en.wikipedia.org/wiki/ML_(programming_language)
We're not reinventing the wheel so much as exploring how certain features might be added to the Chuck language--features that appear in many other languages (JavaScript, Haskell, Python, and ML too). I mean, LISP did this stuff before any of the others...
I just meant that the things you are experimenting with have already been done - there would be problem to add it. Easier. :-) One needs to figure out how to add a type system. But if one scraps the Hindley-Milner type system, at least in the global form it appears in SML and Haskell, there would be less of a problem.
I think it's great to look at the way other languages do things as examples, but we're not about to re-make the Chuck system using Haskell syntax or LISP, or ML. It's highly likely that Chuck will get new features, but the ones it gets will be the ones that seem most important to the devs and the community, I suppose.
Sorry, I treated the actual syntax as irrelevant - it should of course be ChucKish, but what works can be found out when plugging into the .y grammar file. So I thought of x |-> f or \x -> f or fn x => f or (lambda x f) as merely different ways to say the same thing. One can in Haskell use a syntax closer to your: bing :: Num a => a -> a -> a bing b = funk where funk i = b + i It says essentially the same as fun fun int bing(int b) { fun int funk(int i) { return b+i; } return funk; } though strictly speaking, the return type is "fun int (int)" or something. The problem is probably not adding functions as objects, but finding a good type system, especially when polymorphy is added. Hans
I see, yes. Would this essentially give us something like a dynamically
typed Chuck? I would love that... but I think that we're going to get
serious resistance from the devs on this one. I think you're right,
though. If we had a better type system, then none of this kind of stuff
would be such a hurdle to get over.
I personally, really appreciate what LiCK does for Chuck, but I think it's a
lot of boiler plate to write, when having a more flexible language
implementation / type system would allow us to avoid all that.
-mike
On Sun, Jan 10, 2010 at 5:34 PM, Hans Aberg
On 10 Jan 2010, at 22:38, mike clemow wrote:
You are sort of reinventing the wheel, or at least (Standard) ML, here.
See http://en.wikipedia.org/wiki/Standard_ML http://en.wikipedia.org/wiki/ML_(programming_language)http://en.wikipedia.org/wiki/ML_%28programming_language%29
We're not reinventing the wheel so much as exploring how certain features might be added to the Chuck language--features that appear in many other languages (JavaScript, Haskell, Python, and ML too). I mean, LISP did this stuff before any of the others...
I just meant that the things you are experimenting with have already been done - there would be problem to add it. Easier. :-)
One needs to figure out how to add a type system. But if one scraps the Hindley-Milner type system, at least in the global form it appears in SML and Haskell, there would be less of a problem.
I think it's great to look at the way other languages do things as
examples, but we're not about to re-make the Chuck system using Haskell syntax or LISP, or ML. It's highly likely that Chuck will get new features, but the ones it gets will be the ones that seem most important to the devs and the community, I suppose.
Sorry, I treated the actual syntax as irrelevant - it should of course be ChucKish, but what works can be found out when plugging into the .y grammar file. So I thought of x |-> f or \x -> f or fn x => f or (lambda x f) as merely different ways to say the same thing.
One can in Haskell use a syntax closer to your:
bing :: Num a => a -> a -> a bing b = funk where funk i = b + i It says essentially the same as
fun fun int bing(int b) { fun int funk(int i) { return b+i; } return funk; } though strictly speaking, the return type is "fun int (int)" or something.
The problem is probably not adding functions as objects, but finding a good type system, especially when polymorphy is added.
Hans
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
On 10 Jan 2010, at 23:47, mike clemow wrote:
I see, yes. Would this essentially give us something like a dynamically typed Chuck? I would love that... but I think that we're going to get serious resistance from the devs on this one. I think you're right, though. If we had a better type system, then none of this kind of stuff would be such a hurdle to get over.
No - Haskell is statically typed. And so are the C++ templates.
I personally, really appreciate what LiCK does for Chuck, but I think it's a lot of boiler plate to write, when having a more flexible language implementation / type system would allow us to avoid all that.
If one wants to implement libraries, it is nice to have some kind of polymorphy. So I think that might be the hurdle. As for a lambda calculus, that would be nice, and ChucK does not need something advanced. One needs to decide on an evaluation model. Scheme uses applicable order - evaluate arguments first, and then expand the lambda expression. The other way around is normal order, which may be better with infinite and imperative structures. Haskell uses as default lazy evaluation, which means that arguments are only evaluated to the extent needed and intermediate results can be cached. This is wholly incompatible with imperative structures, so Haskell uses the complicated construct of monads to handle that via the type system. Nothing for ChucK which is so imperative. But one can also call for strict evaluation, same as in C/C++ and I gather ChucK and perhaps the same as the applicable order above. So one can have more than one evaluation model. Hans
I think I'm going to add trying to understand the major benefits of dynamic
typing and closures/lambda to my wishlist for the new year (I feel old every
time I read stuff like this... I just see hard-to-read and hence unmanagable
code as being the result). Mike or anyone, do you have any pointers to good
articles explaining this?
Anyway, on my wishlist is a facility for easily writing your own UGen code
in ChucK. Maybe some system for making dynamically linked libraries that
could be included into the ChucK VM?
Happy ChucK Year Everyone!
/Stefan
2010/1/10 mike clemow
I see, yes. Would this essentially give us something like a dynamically typed Chuck? I would love that... but I think that we're going to get serious resistance from the devs on this one. I think you're right, though. If we had a better type system, then none of this kind of stuff would be such a hurdle to get over.
I personally, really appreciate what LiCK does for Chuck, but I think it's a lot of boiler plate to write, when having a more flexible language implementation / type system would allow us to avoid all that.
-mike
On Sun, Jan 10, 2010 at 5:34 PM, Hans Aberg
wrote: On 10 Jan 2010, at 22:38, mike clemow wrote:
You are sort of reinventing the wheel, or at least (Standard) ML, here.
See http://en.wikipedia.org/wiki/Standard_ML http://en.wikipedia.org/wiki/ML_(programming_language)http://en.wikipedia.org/wiki/ML_%28programming_language%29
We're not reinventing the wheel so much as exploring how certain features might be added to the Chuck language--features that appear in many other languages (JavaScript, Haskell, Python, and ML too). I mean, LISP did this stuff before any of the others...
I just meant that the things you are experimenting with have already been done - there would be problem to add it. Easier. :-)
One needs to figure out how to add a type system. But if one scraps the Hindley-Milner type system, at least in the global form it appears in SML and Haskell, there would be less of a problem.
I think it's great to look at the way other languages do things as
examples, but we're not about to re-make the Chuck system using Haskell syntax or LISP, or ML. It's highly likely that Chuck will get new features, but the ones it gets will be the ones that seem most important to the devs and the community, I suppose.
Sorry, I treated the actual syntax as irrelevant - it should of course be ChucKish, but what works can be found out when plugging into the .y grammar file. So I thought of x |-> f or \x -> f or fn x => f or (lambda x f) as merely different ways to say the same thing.
One can in Haskell use a syntax closer to your:
bing :: Num a => a -> a -> a bing b = funk where funk i = b + i It says essentially the same as
fun fun int bing(int b) { fun int funk(int i) { return b+i; } return funk; } though strictly speaking, the return type is "fun int (int)" or something.
The problem is probably not adding functions as objects, but finding a good type system, especially when polymorphy is added.
Hans
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
-- http://michaelclemow.com http://semiotech.org
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
-- Release me, insect, or I will destroy the Cosmos!
On 11 Jan 2010, at 11:21, Stefan Blixt wrote:
I think I'm going to add trying to understand the major benefits of dynamic typing and closures/lambda to my wishlist for the new year (I feel old every time I read stuff like this... I just see hard-to- read and hence unmanagable code as being the result). Mike or anyone, do you have any pointers to good articles explaining this?
The best way, next to writing your own language, is probably to to try out writing some code. I use Hugs http://haskell.org/hugs/, which is a very good HAskell interpreter - so it is similar to ChucK in that way. One can write code interactively against a module. So this would be like a chuck interactive mode. The module must be in a file though. There are tutorials, the main one I would recommend is http://www.haskell.org/tutorial/ but there are others: http://haskell.org/haskellwiki/Tutorials There is a package for doing MIDI http://haskell.org/haskellwiki/Haskore An alternative might be http://en.wikipedia.org/wiki/OCaml, an objective derivation of ML/SML. Don't know much about it These are statically typed languages. Here is a list of dynamically typed languages: http://en.wikipedia.org/wiki/Dynamic_typing#Dynamic_typing I think that GNU Guile has a dynamic OO package, if you like LIPS syntax: http://en.wikipedia.org/wiki/GNU_Guile Hans
On 10 Jan 2010, at 19:59, mike clemow wrote:
1 => foo;
this is sane, but this isn't:
1 => foo => bar;
foo(1) is the same as 1 => foo
foo => bar is the same as bar(foo)
When combining, one need to specify a binding order. Should it bind to the left, like say +: (1 => foo) => bar; or to the right, as for example the assignment operator = in C/C++: 1 => (foo => bar); One can be the default, and the other can be invoked by the use of parenthesizes. Such combinations are quite useful in C++ as "manipulators" of IO- streams. For example, chin => parser => value; Here, the manipulator parser() could be a function that takes a chin as an argument, parsers it, and returns a value. Hans
Mike 1 => foo;
this is sane,
Agreed.
but this isn't:
1 => foo => bar;
foo(1) is the same as 1 => foo
foo => bar is the same as bar(foo)
Yes... But look at this; 60 => Std.mtof => my_osc.freq; That's good ChucKian form, I'd say. It's compact, it's coherent and it's very readable, almost like a chronological sentence, like "I put on my coat and went outside"
however, I was suggesting that I could assign the object/function foo to reference bar this way:
foo @=> bar;
which means this:
1 => bar;
would now return 3 because bar is now a reference to the same function foo is a reference to.
see what I mean?
Yes, I do, but when functions become objects then the code becomes ambiguous for overloaded to take both functions and integers as parameters. If my_osc.freq above would be overloaded to also take functions as a argument then that line become a bit like "I was walking my dog when I met a girl, then I brushed her hair.". That sentence might mean I brushed my dog or I might have brushed the girl's hair. You and me would probably never use a sentence like that because it's asking for misunderstandings, but it's perfectly fine English. Formal languages should really not have that sort of sentence, I feel, and I don't see how we can get around this with your plan as it stands. I'm certainly not saying here that I think functions as objects or as arguments are inherently a bad idea, in fact I think it might be a very good one. As it stands, though, I think your proposal has some issues and I wouldn't like to break or lovely feature of chaining function-calls into single lines of code where that makes sense. Are we on the same page again? Am I still misunderstanding something? Yours, Kas.
Kas,
No, you're not misunderstanding anything! I got a little confused... you
can do two things with chaining in chuck. one is a double-assignment (which
is what I thought was happening):
1 => int i => int j;
the other is passing args to functions:
fun int foo(int i)
{
return i+1;
}
1 => foo; // returns 2
but, if we did like you suggested:
fun void bar(int b)
{
<<< "hi", b >>>;
}
then this:
1 => foo => bar;
will print "hi 2". but what i was missing was the fact that 1 => foo
returns 2 and passes that to bar. which is different from the double
assignment. if foo didn't return an int, the above wouldn't be possible.
for instance, if foo was changed to this:
fun void foo(int i)
{
//return i+1;
<<< i >>>;
}
then the line
1 => foo => bar;
would fail with this error:
[Untitled 2]:line(12): argument type(s) do not match:
[Untitled 2]:line(12): ... for function 'bar(...)' ...
[Untitled 2]:line(12): ...(please check the argument types)
All I was saying originally, however, was that we should overload @=> to be
able to reassign functions themselves to other references.
fun void foo(int i)
{
<<< i >>>;
}
foo @=> fun void foo2;
1 => foo2; // prints 1
Sorry about the confusion--I think we agree, I'm just being lazy in my
explanations. ;-) all work and no play makes mike a dull boy. all work
and no play...
Abort, Retry, Fail,
Mike
:)
2010/1/11 Kassen
Mike
1 => foo;
this is sane,
Agreed.
but this isn't:
1 => foo => bar;
foo(1) is the same as 1 => foo
foo => bar is the same as bar(foo)
Yes... But look at this;
60 => Std.mtof => my_osc.freq;
That's good ChucKian form, I'd say. It's compact, it's coherent and it's very readable, almost like a chronological sentence, like "I put on my coat and went outside"
however, I was suggesting that I could assign the object/function foo to reference bar this way:
foo @=> bar;
which means this:
1 => bar;
would now return 3 because bar is now a reference to the same function foo is a reference to.
see what I mean?
Yes, I do, but when functions become objects then the code becomes ambiguous for overloaded to take both functions and integers as parameters. If my_osc.freq above would be overloaded to also take functions as a argument then that line become a bit like "I was walking my dog when I met a girl, then I brushed her hair.". That sentence might mean I brushed my dog or I might have brushed the girl's hair. You and me would probably never use a sentence like that because it's asking for misunderstandings, but it's perfectly fine English. Formal languages should really not have that sort of sentence, I feel, and I don't see how we can get around this with your plan as it stands.
I'm certainly not saying here that I think functions as objects or as arguments are inherently a bad idea, in fact I think it might be a very good one. As it stands, though, I think your proposal has some issues and I wouldn't like to break or lovely feature of chaining function-calls into single lines of code where that makes sense.
Are we on the same page again? Am I still misunderstanding something?
Yours, Kas.
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
This may in fact cause problems in ChucK with its heavy overloading of the Chuck operator not => but perhaps with the new <=. One would expect 1 => foo => bar; to bind to the left, as (1 => foo) => bar; This will then also work with input streams (not yet implemented in ChucK): chin => foo => bar; should mean: first foo(chin), and pass the return value to bar. Now reverse this, using <=. If it works like an ordinary assignment, one should write bar <= foo <= 1; and here => should (by common expectation) be binding right: bar <= (foo <= 1); First pass 1 to foo, and the result to bar. But for output streams, it should bind to the left: chout <= foo <= bar; (chout <= foo) <= bar; First pass chout to foo, and the pass the result to bar. On streams, there is no semantic difference between => and <=; they are just used as eye-candy to show the difference between input and output. But for assignments, there is a difference in binding to the left and to the right. Hans On 11 Jan 2010, at 19:19, mike clemow wrote:
No, you're not misunderstanding anything! I got a little confused... you can do two things with chaining in chuck. one is a double-assignment (which is what I thought was happening):
1 => int i => int j;
the other is passing args to functions:
fun int foo(int i) { return i+1; }
1 => foo; // returns 2
but, if we did like you suggested:
fun void bar(int b) { <<< "hi", b >>>; }
then this:
1 => foo => bar;
will print "hi 2". but what i was missing was the fact that 1 => foo returns 2 and passes that to bar. which is different from the double assignment. if foo didn't return an int, the above wouldn't be possible.
for instance, if foo was changed to this:
fun void foo(int i) { //return i+1; <<< i >>>; }
then the line
1 => foo => bar;
would fail with this error:
[Untitled 2]:line(12): argument type(s) do not match: [Untitled 2]:line(12): ... for function 'bar(...)' ... [Untitled 2]:line(12): ...(please check the argument types)
On 11 Jan 2010, at 19:19, mike clemow wrote:
All I was saying originally, however, was that we should overload @=> to be able to reassign functions themselves to other references.
fun void foo(int i) { <<< i >>>; }
foo @=> fun void foo2;
1 => foo2; // prints 1
This is possible in SML. This can cause some unexpected code:
fun twice x = 2*x;
fun increment x = x + 1;
...
val twice = increment;
and now the function twice instead increments.
The code in Haskell is:
twice x = 2*x;
increment x = x + 1;
twice = increment;
and it produces this error in Hugs:
ERROR "Twice.hs":23 - "twice" multiply defined
even producing a joke. :-)
Haskell prohibits it because the renaming of functions seem dangerous
- it is not needed in programming, really.
Instead has a module system. In Haskell, it has to be in one file. One
writes:
module Twice (
Kassen wrote:
We need the context-sensitive block processing <snip> That one should be a big leap in performance, after that we may have to think about multi-core support.
It's interesting to see that all posts in this thread is about language-stuff, except my wish and your reply. I'm restating: I think I'm pretty alone with this wish, and no matter how much I love chuck (and I do) it forces me to look elsewhere :-( -- Atte http://atte.dk http://modlys.dk
FWIW, I hit the roof every now and then, usually when I've coded up some
sound-making thing that I try to multiply into several voices.
I don't know all the jargon, but intuitively something like a UGen feels
like you should be able to run it in a thread of its own - all it needs to
share are its inputs and outputs... but if Ge says its hard to do I'm not
the one to debate against.
/Stefan
On Thu, Jan 7, 2010 at 9:03 AM, Atte André Jensen
Kassen wrote:
We need the context-sensitive block processing <snip> That one should
be a big leap in performance, after that we may have to think about multi-core support.
It's interesting to see that all posts in this thread is about language-stuff, except my wish and your reply.
I'm restating: I think I'm pretty alone with this wish, and no matter how much I love chuck (and I do) it forces me to look elsewhere :-(
-- Atte
http://atte.dk http://modlys.dk _______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
-- Release me, insect, or I will destroy the Cosmos!
2010/1/7 Stefan Blixt
I don't know all the jargon, but intuitively something like a UGen feels like you should be able to run it in a thread of its own - all it needs to share are its inputs and outputs... but if Ge says its hard to do I'm not the one to debate against.
I think there are two main barriers to multi-threading UGen processing. UGens are fairly independent, but 1) changes to the graph need to be synchronous with ChucK time and 2) the minimum block size you can use is dependent on how much virtual time there is before the VM needs to wake up again, and how tight a feedback loop a particular UGen is in. (1) means UGen processing needs to start and stop in time with the VM (synchronization overhead). The naive solutions for (2) have weird side-effects that make it worth doing right, which would involve making guesses about the next time external messages (like from Hid or MIDI) could wake a shred (window size is a convenient guess and probably wouldn't decrease timing accuracy by much), and analyzing the graph to find feedback loops and set block sizes accordingly. -- Tom Lieber http://AllTom.com/ http://ckvlang.org/
Stefan Blixt wrote:
I don't know all the jargon, but intuitively something like a UGen feels like you should be able to run it in a thread of its own
I'm not sure how multi-threading UGens should improve performance. If it's a matter of using both cores of my dual core, it's only a 100% speedup, which would be a start, but won't last long. Some of you might remember that I did some "benchmarks" on UGens (http://atte.dk/chuck/) and although it's extremely un-scientific it suggests for instance that a SndBuf uses 0.5% of my cpu power. Doesn't sound like much, but it takes two to make stereo and I don't think it's ambitious to have 20 sounds play at the same time (a couple of chords, a bass, some melody and some rhythm) which is using 20% for that alone. Then I haven't even started with the fun stuff of using filters, echo (reverb is too heavy on the cpu and can only be applied occationally). Add to that the "playing-code" that's gonna drive the thing. Chuck starts to be unstable around 70% at the most here, so the fun is limited. NB1: Correction: my cpu is only 2.0GHz dual core, not 2.4GHz as I stated earlier. NB2: I often thought that I was somehow bitten by some evil hardware/os/setup issue that made chuck perform severely bad on my setup, but now I've come to the conclusion (after extensive testing, system tweaking, trying out other linux distros, abandoning X, trying other laptops) that it's the general picture. NB3: Let me say it again: I'm in no way trying to bash chuck. I love it as everyone here, I just feel forced to switch to for instance supercollider or something. -- Atte http://atte.dk http://modlys.dk
participants (11)
-
Adam Tindale
-
Atte André Jensen
-
Hans Aberg
-
Joe McMahon
-
joerg piringer
-
Kassen
-
Michael Heuer
-
mike clemow
-
Robert Poor
-
Stefan Blixt
-
Tom Lieber