User loginNavigation |
LtU ForumThe Problem with "dup" and "swap" in Stack-Based LanguagesOperations like "dup" and "swap" in stack-based languages are special in that they return multiple results (unlike most other languages which simulate multiple results by returning tuples). I find expressing the concept in a type system challenging (if anyone else has done it successfully I would definitely like to hear about it). One of the core problems is that the type of a function like eval, which is supposed to execute any function: eval : (a (a -> b) -> b) This makes a lot of sense when a function only has one argument and one result. I can reduce every function to an equivalent one having one argument: (a b -> c) = (a -> b -> c) But I do not know how to reduce a function to having one result. This leads to specific problems with certain terms, which I go into more depth on my blog ( http://cdiggins.com/2006/12/09/type-ambiguity-in-cat-and-the-importance-of-formalization/ ). The only solution I can think of is to creat another eval functions which returns two results: eval2 : (a (a -> b c) -> b c) Any thoughts? Continuations and freeing the stackFor an error recovery system that supports resume, I was thinking of packing the current continuation in the exception object. However, that raises an issue with freeing the resources: even though the program pointer escaped the context of the error, there is still a way to return there with "resume". For example: def foo(x) = 3 + (50 / x) ... foo 0 catch e : DivisionByZero e.resume 42 #the answer is 42 | other throw other How do you normally deal with continuations that are returned from the current context? Commercial Users of Functional Programming 2006
abstracts and slides ExceptionsThis may be a naive question from an unlearned youngster, but I'm wondering if there has been research into alternatives to exceptions as a means of detecting and dealing with runtime errors. The practice of returning error codes is usually discouraged in favor of exceptions for good reasons. Exceptions are sure to be caught somewhere in some way, or else they can cause the program to die with perhaps a moderately useful error message, trigger a debugger in a structured way, etc. Exceptions that aren't being handled can be checked for (using a language with a type system that can do that sort of thing, anyway), and that's often a handy thing to be able to do. Error codes, on the other hand, are very arbitrary, can have overlapping ID numbers, don't carry extra information, etc. Exceptions, though, seem to carry with them their own baggage and limitations. Sometimes that baggage is nothing more than perceived syntactic "ugliness," but I think there's a little more to it than that. Perhaps I'm just not well versed enough in PL theory (and perhaps real life experience) to really "get" it, but it seems slightly wrong/ugly (to me) that an exception usually takes you out of the normal flow of code and into a kind of mystical land of uncertainty where an error in one situation may lead to being caught in routine X, but the same error in another situation is caught in routine Y - leaving all of the state in between somewhat ambiguous. I realize that many languages have mechanisms for handling those situations (like "finally" blocks to clear up things before you leave the scope for good), but that all feels a bit like the tedium associated with manual memory management rather than the live-and-let-live approach of garbage collection. For example, say a block of code is writing to an output file and it runs out of disk space. The write() call causes an exception. This exception may not be handled in the routine that was doing the writing on account that the original author may have figured it'd be best for the higher-level logic to decide what to do. Okay - so this exception is thrown and it's a low-level "disk full" kind of error. It ends up getting caught way high up in the logic tree where the programmer originally had called something like: myObject.save(). At that stage in the logic, the programmer should be thinking abstractly about his/her problem and not be so much concerned that the object is being saved to disk, a database, or whatever. But it turns out that now there has to be code there to catch rather specific errors like "disk full." Obviously that write() exception could have been caught earlier and transformed into something more general, but how far are you willing to go? When do you break down and do a catch( * ) { throw Exception('something bad happened') }? On top of all that, where does the application decide on how to proceed? Should it erase the output file on account that it's likely corrupted now and in a half-finished state? Or should it leave it there as-is? What if the application needs to ask the user? How do you pass the answer back down the chain from the UI to the business logic layer that does the actual work? (Note: This may be a badly engineered example, but I think it's a reasonably realistic one that reflects the kinds of problems that crop up in real code that's not been well engineered but can't be thrown away and rewritten from scratch due to time/budget/political pressures.) Anyway, I'm interested in hearing about other approaches to handling runtime errors that may have popped up over the years and, perhaps, information as to why exceptions are the apparently preferred method of doing things by the mainstream (and even not-so-mainstream) languages. Is it simply because there hasn't been any better alternatives? Or are there much better reasons which I am simply missing the point of. :-) eskimo: experimenting with skeletons in the shared address model.eskimo: experimenting with skeletons in the shared address model. M. Aldinucci, 2003.
Based on some simple extensions to C, the library allows to work on large distributed structures following compositional functional semantics.
By Denis Bredelet -jido at 2006-12-07 22:33 | LtU Forum | login or register to post comments | other blogs | 7435 reads
Typing a function which includes its axioms?I'm trying to figure out how to type a function and include a set of axioms at the same time. Here's a concrete example.. Let's say I decide to build a system which uses Natural numbers:
Nat = Z
| Succ( Nat )
Now I want to be able to add two Nats together in one of the system's modules so I define a function called Add for this purpose. Its type (pseudo-haskell): Add :: a -> a -> a And a version which implements addition of Naturals (using rewrite rule notation): Add( x Z ) = x Add( x Succ( y ) ) = Succ( Add( x y ) ) Note that Add does not restrict the type of its arguments to Nat, since I may want to introduce a version which adds Int, or Real down the road. However, when I use Add in the system, I expect it to follow some basic axioms:
Add( a b ) = Add( b a )
Add( Add(a b) c ) = Add( a Add(b c) )
There exists some Z such that: Add( a Z ) = a
etc..
Basically, I want to include these axioms as part of the TYPE of Add.. If someone writes a version of Add which does not also fulfill the axioms, there should be a type error. I understand that this means a lot of tricky design to avoid bumping into the Halting Problem during type-checking, but I'm just trying to work out the framework first and maybe there's a side-step I can take later on..
Thanks! "Folding"/FP traversal over treesI've been working on defining a "fold" operation for trees. There was some helpful discussion in the past "Folding over trees", but I haven't been able to find anything beyond the XML-type examples suggested there. My problem: I want to have more control of the traversal. That is, when a certain node is reached I want the possibility of skipping further descent, or reentering an already-traversed node. So yeah, this isn't actually a "fold". Maybe its a "visitor with control"? Olin Shiver's paper "The Anatomy of a Loop" (previously on LtU) discusses a general framework for separating these kinds of concerns.. But I'm looking for something a bit simpler.. (and am doing this in C++ besides) So... any suggestions on general FP approaches to this kind of problem? [hopefully this isn't OT!] (seed 'fup node) => (next-seed, reenter-children?) (seed 'fdown node) => (next-seed, skip-children?) (seed 'fhere leaf) => (next-seed, skip-the-rest-of-the-children?) Languages with first order types and partial evaluationI'm seeking languages which implement following features: 1) Types are first class citizens and can be treated as ordinary values The idea I try to follow can be best described using a little example. Say you have typed variables x:even, y:odd which are not yet bound by values. One can state explicit type rules for an operation add like this: add(x:even, y:even) -> even add(x:odd, y:even) -> odd ... and write down any kind of permutation of argument types. But instead one might compute the types using a function:
type(x) = case mod(x,2) of
1 -> odd
0 -> even
else
`type(x) -- returns unevaluated expression type(x)
with mod(x+y,k:int) = mod(mod(x,k)+mod(y,k),k) -- use pattern matching for decomposition mod(x*y,k:int) = mod(mod(x,k)*mod(y,k),k) mod(x:even,2) = 0 mod(x:odd,2) = 1 Now one can compute z = x*x+y*y+3 and deal with z as a variable of known type and perform type guarded simplifications. Maybe someone has a pointer where to find reading material ( or even language implementations ) that deal with related ideas? The Cat Language Kind SystemMy latest attempt to describe the Cat kind system with some kind of rigour is at http://www.cat-language.com/paper.html. Here is an excerpt from the kind system description:
kind ::==
| type the kind of all types
| stack the kind of all stacks
type ::==
| a type variable
| var variant
| int integer
| bool bool
| string string
| list list
| ∀ ρ . (stack, ρ) -> (stack, ρ) function
stack ::==
| A stack variable
| nil empty stack
| type, stack stack with a single type on top
| stack, stack stack with a stack on top
| stack \ stack stack difference operationI'd be exceedingly greatful for any comments on the paper. Benchmarking and StatisticsI recently posted an excerpt from a Ruby book I'm working on (it's a sidebar from a section on the Benchmark library), but I'm not sure if it's solid enough for publication (my math background isn't up to snuff). I'd love to see/hear what LtUers think about it. Generally the idea is that benchmarking as currently provided by the library is insufficient -- doing one comparison run between options (even a large run) doesn't indicate anything about the statistical significance of the variation between run times of the two (or more) options. So I present a somewhat naive statistical model for doing those comparisons (and in the blog post encourage someone with better Ruby and Math chops to librarify the idea). You can read the post at: Benchmarking, Lies, and Statistics. |
Browse archives
Active forum topics |
Recent comments
8 weeks 3 days ago
8 weeks 3 days ago
8 weeks 4 days ago
8 weeks 4 days ago
9 weeks 1 day ago
9 weeks 1 day ago
9 weeks 2 days ago
9 weeks 2 days ago
9 weeks 2 days ago
9 weeks 2 days ago