On 24/03/2012, at 5:33 AM, Raoul Duke wrote: > On Thu, Mar 22, 2012 at 6:39 PM, john skaller > <skal...@users.sourceforge.net> wrote: >> (a) provide subtyping so D - pure -> C is a subtype >> of D -> C (maybe impure) >> >> (b) also provide variance notation or something which allows >> to transmit the purity (or totality) of the argument to a HOF. > > as a Regular Joe end-user of programming languages, i think i would > want it to be that my functions are marked im/pure with types, or > annotations, or something, and then when i pass them into a hof that > thing gets the same taintedness so that during compile time static > checks the systems knows it is also im/pure.
At present, Felix already "guesses" about purity. There's code already which is applied after optimisation and monomorphisation/instantiation, to calculate whether a function can go on the stack, be a C function, or a heap closure is required, also happens to calculate purity. Purity is useful for reordering: x = f a; y = g b; if f,g are pure, and a,b are transparent, then f a, g b are transparent, and we can also write: y = g b; x = f a; with the same outcome. Another example: for .. do .. x = f a; .. done if a doesn't depend on anything in the loop, we can lift the assignment out of the loop: we know 'f' depends only on a. Felix assumes C bindings are pure. Eg if you write: fun f: int -> int = "someCfun($1)"; it assumes f is pure. This is usually the case, since you can't get a Felix variable into the C code easily :) Of course occasionally it's not the case (woops). The "impure" annotation would be useful there. There are some classic impure functions: most const methods of a C++ class object are impure, they're accessors, they're there to report on the object state: the "get" method people like writing is such an accessor. I have thought this is so common it might be worth var y= 43; accessor f (x: int ) => x + y; i.e actually have a special name for them instead of impure fun f(x:int) => .. or perhaps var fun f (x:int) => ... or even var f (x:int) => ... Actually, I kind of like that last one, it's saying f is a parametrised variable. And we could make val f (x:int) => x; means that f is pure. After all .. did you know you can already write: fun x = y + 20; It's just a function with no arguments. It means "Lazily evaluated". pure, impure, total, and partial are implemented at the moment. I used on a couple of functions in List class and didn't really like it much. I left out the HOF's and of course a lot of list functions are higher order. It seems most useful for C bound functions and leaf functions. But see "const" problem. Are we polluting the language with minor details too much? Annotations have three uses: they help optimisation, and they help readability, and maybe they help assure correctness. Writing: pure fun square (x:int) => x * x; doesn't seem to help with readability IMHO, it makes it harder to read. val square (x:int) => x * x; is cleaner. Actually: square (x:int) := x * x; seems consist with the usual y := x * x; and actually: square := fun (x:int) => x * x; is tempting (and already possible!) though it won't overload. YMMV. What's this to do with purity of HOFs? Well to some extent the question is: what do you expect? What looks clean and nice? What would help you predict behaviour and check correctness? > the const problem of course, which is the same as the oh i just added > the use of a monad problem, same as the oh my utility function needs > one more parameter: you make some "small" change at the bottom of some > code, and then you are forced to go and change 43.7% of your entire > code base. which sucks. but might be the Right Thing To Do even though > it sucks. It might, but probably not. in the case of "const" I think not. I think this was a serious mistake. Which is why it is left out of Felix. Guess what? I don't miss it at all. Haven't seen any code where it matters much. Haven't seen any bugs from casting away const (Felix casts it away if a C binding function returns const). Const sucks: the contract is too weak to bother. It doesn't even allow caching because of aliasing. What Felix does is much better: it has "val" which names values, and the named value isn't a variable so it can't be addressed. The compiler can still store the value in a location and pass the address of the location, the receiving function would have to be generated to accept the pointer. In this case the *compiler* ensures semantics. There can't be any aliasing because the address is secret. Pass by value is vastly superior. C++ made a really serious mistake with const references. It's better to pass a value even for a huge data structure .. and let the compiler sort out how to avoid copying. Pass by value allows a number of optimisations that pass by pointer (i.e. by reference) does not. It's generally much faster to pass by value that a reference, even if the data structure is 8 words vs one pointer: copying is really fast on modern processors with pipelining and caching compared to repeated dereferencing. The biggest gain is inlining: the "copy" of pass by value just goes away then. It's much harder to get rid of pointers. > dunno. i'd suggest asking on LtU :-) to see if there's already work > done on how to handle such "tainting"? Possible .. though there'd be a long winded discussion of the merits of pure annotation in an imperative language .. which would lead to few conclusion. It could be handled much better if Felix supported implicit subtyping, but except for wrapper generation it doesn't. The exact matching rule for overloads precludes easy subtyping. In a language without overloading, subtyping is easier to support, since you know what function is called, you know what conversion is required and can accept or reject it. I have to add: if you're also doing HM-polymorphism it sucks. I dislike implicit typing more and more. I'm debugging a problem at the moment with "inherit" clause and I spend most of my time trying to guess what the types of things are so I can print them. Sometimes if I get it wrong it breaks code further down the track because it happens the type hadn't been deduced yet. I actually write: print_endline x; and hope it fails with a message that tells me the type of x.. :) -- john skaller skal...@users.sourceforge.net http://felix-lang.org ------------------------------------------------------------------------------ This SF email is sponsosred by: Try Windows Azure free for 90 days Click Here http://p.sf.net/sfu/sfd2d-msazure _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language