Re: [Haskell-cafe] How to translate Haskell to other languages?
Hi Jason, I don't know Python, but let me share some thoughts that you might find useful. First, a few questions about your manual translations. Are your functions curried? For example, can I partially apply zipWith? Also, you put a thunk around things like cons(...) --- should it not be the arguments to cons that are thunked? Now, on to an automatic translation. As you may know already, Haskell programs can be transformed to combinator programs which are quite simple and easy to work with. Here is what I mean by a combinator program: p ::= d*(a program is a list of combinator definitions) d ::= c v* = e (combinator definition) e ::= e e (application) | v (variable/argument) | c (constant: integer literal, combinator name, etc.) As an example of a combinator program, here is one that reverses the list [0,1,2]. rev v acc = v acc (rev2 acc) rev2 acc x xs = rev xs (cons x acc) cons x xs n c = c x xs nil n c = n main = rev (cons 0 (cons 1 (cons 2 nil))) nil This program does not type-check in Haskell! But Python, being dynamically typed, doesn't suffer from this problem. :-) A translation scheme, D[], from a combinator definition to a Python definition might look as follows. D[c v* = e] = def c() : return (lambda v1: ... lambda vn: E[e]) E[e0 e1] = E[e0] (E[e1]) E[v] = v E[c] = c() Here is the result of (manually) applying D to the list-reversing program. def nil() : return (lambda n: lambda c: n) def cons() : return (lambda x: lambda xs: lambda n: lambda c: c(x)(xs)) def rev2() : return (lambda acc: lambda x: lambda xs: rev()(xs)(cons()(x)(acc))) def rev() : return (lambda v: lambda acc: v(acc)(rev2()(acc))) def main() : return (rev() (cons()(0)( cons()(1)( cons()(2)( nil()(nil())) The result of main() is a partially-applied function, which python won't display. But using the helper def list(f) : return (f([])(lambda x: lambda xs: [x] + list(xs))) we can see the result of main(): list(main()) [2, 1, 0] Of course, Python is a strict language, so we have lost Haskell's non-strictness during the translation. However, there exists a transformation which, no matter how a combinator program is evaluated (strictly, non-strictly, or lazily), the result will be just as if it had been evaluated non-strictly. Let's call it N, for Non-strict or call-by-Name. N[e0 e1] = N[e0] (\x. N[e1]) N[v] = v (\x. x) N[f] = f I've cheekily introduced lambdas on the RHS here --- they are not valid combinator expressions! But since Python supports lambdas, this is not a big worry. NOTE 1: We can't remove the lambdas above by introducing combinators because the arguments to the combinator would be evaluated and that would defeat the purpose of the transformation! NOTE 2: i could be replaced with anything above --- it is never actually inspected. For the sake of interest, there is also a dual transformation which gives a program that enforces strict evaluation, no matter how it is evaluated. Let's call it S for Strict. S[e0 e1]= \k. S[e0] (\f. S[e1] (\x. k (f x))) S[v]= \k. k v S[f]= \k. k f I believe this is commonly referred to as the CPS (continuation-passing style) transformation. Now, non-strict evaluation is all very well, but what we really want is lazy evaluation. Let's take the N transformation, rename it to L for Lazy, and indulge in a side-effecting reference, ML style. L[e0 e1] = L[e0] (let r = ref None in \x. match !r with None - let b = L[e1] in r := Some b ; b | Some b - b) L[v] = v (\x. x) L[f] = f I don't know enough to define L w.r.t Python. I haven't tried too hard to fully understand your translation, and likewise, you may not try to fully understand mine! But I thought I'd share my view, and hope that it might be useful (and correct!) in some way. Matthew. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] FPGA / Lava and haskell
Hi Marc, The Chalmers Lava homepage tells abouta Xilinx version which should be merged in soon. But on the xilinx homepage there was no reference to neither Lava nor haskell.. I'm thinking about designing a similar tool to www.combimouse.com. you also might consider using a PIC or some such microcontroller for this kind of project. I don't think there is a Haskell library for PIC programming, but it would be fun to make one! For somewhat related work, see issues 6 and 7 of The Monad.Reader (http://www.haskell.org/haskellwiki/The_Monad.Reader), especially Russell O'Conner's article. As mentioned in issue 7, I did use Lava to program an RCX microcontroller, but in general the techniques I used are much better suited to hardware. Also, there is PICBIT: A Scheme System for the PIC Microcontroller by Marc Feeley (http://www.iro.umontreal.ca/~feeley/papers/sw03.pdf) which might be of interest. Regarding Lava, there is a version on Satnam Singh's website (http://raintown.org/lava/). I use Emil Axelsson's version of Chalmers Lava (http://www.cs.chalmers.se/~emax/darcs/Lava2000/) that works with the latest GHC. I made some mods to target the Xilinx toolset and to provide very basic support for block RAMs (http://www.cs.york.ac.uk/fp/darcs/reduceron2/Lava2000/). I wish I had time to work more on this, and make it more accessible to others! Nevertheless, Chalmers Lava as it stands is already very usable. It is also very hacker-friendly, so I can recommend diving in! As an aside: I'm currently finishing off a document about my uses of Lava and its capabilities/weaknesses. Hopefully this will be publicly available soon. Matt. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Copy on read
Hi Andrew, my probably dodgy reason for mentioning deforestation is that sharing of intermediate values is a major stumbling block; code that uses data linearly is possibly well suited for deforesting. See Frankau's SASL for a language that deforests all lists simply by not letting you copy them! (IIRC there is another constraint that forbids accumulating parameters too.) Similarly, there are recursion patterns for which fusion isn't very easy. Yep, I suspect you're right. That's why most array-based code is explicitly in-place. wouldn't it be nice if it didn't have to be? I agree. As an aside, DiffArray looks quite nice: http://www.haskell.org/haskellwiki/Modern_array_libraries ``if a diff array is used in a single-threaded style, ..., a!i takes O(1) time and a//d takes O(length d).'' Notice the use of seq in 2nd example to enforce a kind of single-threaded behaviour. Seems nasty! I wonder if this could be avoided by providing a (*!*) such that arr *!* i = seq x (arr, x) where x = arr ! i It returns a new array which the programmer should use if they want single-threaded behaviour. Matt. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Copy on read
Uniqueness typing does not lead to in-place update. If a value is only used once, then there is no need to update it at all! my understanding is that if a value is uniquely-typed then it is statically known never to have more than one reference, thus it can be modified in-place. Some potential advantages seem to be: * Less heap is used, reducing the strain on the garbage collector. * Memory writes can sometimes be avoided. Imagine changing the value of a leaf in a large unique tree. Only one memory write is required rather than N, where N is the length of the path to that leaf from the root. Such paths can obviously be quite long when working with lists. Also, the cost of rebuilding constructors with many fields -- only to change a single field -- could be expensive. I wonder to what extent deforestation supersedes such optimisations. This would be a good topic to raise with a Cleaner. The paper Neil mentions looks like a nice alternative to uniqueness typing -- and it appears that there will be a FitA talk about it, this Thursday. Matt. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Functional board games
Hi Dougal, Does anyone know of functional-style implementations of chess/draughts/go/anything else that might give me ideas? there's the Mate-in-N solver in the nofib suite: ftp://www.cs.york.ac.uk/pub/haskell/nofib.tar.gz It takes quite a simple approach, representing the board as two lists (white and black) of piece/square pairs, where a square is just a pair of ints. Matt. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Designing DSL with explicit sharing [was: I love purity, but it's killing me]
Hi Oleg, at the possible risk of straying from Tom's original problem, consider the following generator that could conceivably occur in practice: sklansky f [] = [] sklansky f [x] = [x] sklansky f xs = left' ++ [ f (last left') r | r - right' ] where (left, right) = splitAt (length xs `div` 2) xs left' = sklansky f left right' = sklansky f right test_sklansky n = runState sk exmap0 where sk = sequence (Prelude.map unA (sklansky add xs)) xs = Prelude.map (variable . show) [1..n] (Example due to Chalmers folk, Mary Sheeran and Emil Axelsson; sklanksy is similar to scanl1, but contains more parallelism.) If a 128-bit processor were being developed, sklansky could reasonably be passed 128 elements, *Main test_sklansky 128-- on an AMD64 2200 (3.71 secs, 296129440 bytes) and could form part of a larger expression, and be called several times. So I think this is close to a real situation where CSE is not practical. But like you say, a human would not write such a humungous expression by hand; hand-written expressions may therefore be ideal for crunching by your CSE method. Still, we might like to write generators like sklansky. Hope is offered by the new let_ construct, but it's not clear how to use it in this case. The problem is that sklansky is a function over lists of expressions rather than single expressions, and the let_ construct can only bind single expressions and return single expressions. To write sklansky using your approach, it seems (to me) that the DSL's expression type needs to be extended to support lists. Will this not be complicated and introduce notational inconvenience? (In an earlier post, I outlined a method for embedding algebraic data types in Haskell, and it does have some notational burden.) Matt. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Designing DSL with explicit sharing [was: I love purity, but it's killing me]
Hi Oleg, it's not immediately clear (to me at least) how efficient your method will be in practice. Any method based on common sub-expression elimination surely must inspect every node in the flattened graph. In the worst case, an acyclic graph containing n nodes could have 2^n nodes when flattened to a tree: tricky 0 = constant 0 tricky d = add g g where g = tricky (d-1) Of course, in practice the worst case may not occur. Also, my mental model is big circuits, which may be different to yours and Tom's. (Sorry if I'm just pointing out the obvious.) Matt. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Designing DSL with explicit sharing [was: I love purity, but it's killing me]
Hello again, since Oleg presented an approach to the sharing problem that works on acyclic graphs, I may as well mention an alternative, pure, standard Haskell solution which is to express the fork points in the circuit (or expression), i.e. the points at which an expression is duplicated. You need to introduce a fork primitive: fork :: Bit - (Bit, Bit) or fork :: Exp - (Exp, Exp) This fits quite naturally in the context of circuit description, and I called it expressible sharing. Under some mild restrictions, it even works on cyclic graphs. In particular, it works nicely for regular circuits. The tricky example I mentioned earlier would be written: tricky 0 = constant 0 tricky d = add e0 e1 where (e0, e1) = fork (tricky (d-1)) However, in the end I admitted defeat and decided I preferred observable sharing! Matt. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Designing DSL with explicit sharing [was: I love purity, but it's killing me]
tricky 0 = constant 0 tricky d = add e0 e1 where (e0, e1) = fork (tricky (d-1)) Oops, I just realised that this isn't a very good example of expressible sharing! The problem is that it doesn't take any inputs, and expressible sharing just collapses (partially evaluates) operators when they are applied to constants. A better example would be something that takes an input, such as distrib a [] = [] distrib a (x:xs) = (a0, x) : distrib a1 xs where (a0, a1) = fork a Matt. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] I love purity, but it's killing me.
Hi Tom, So is the general strategy with observable sharing to use unsafePerformIO with Data.Unique to label expressions at construction? something like that, yes. Basically, you just need: {-# NOINLINE ref #-} ref x = unsafePerformIO (newIORef x) and you can write expressions like ref False == ref False and let x = ref False in x == x However, while referential equality is enough for sharing detection, I *suspect* it's simpler to use the fact that refs are IORefs and you can read and write them (in the IO monad). So a very simple Lava might look like module Lava (Bit,Netlist,low,high,nand2,netlist) where import Data.IORef import System.IO.Unsafe {-# NOINLINE ref #-} ref x = unsafePerformIO (newIORef x) type Ref = IORef (Maybe Int) data Bit = Gate String Ref [Bit] type Netlist = [(String, Int, [Int])] -- gate, output, inputs low = Gate low (ref Nothing) [] high = Gate high (ref Nothing) [] nand2 (a, b) = Gate nand2 (ref Nothing) [a, b] netlist :: Bit - IO Netlist netlist x = do i - newIORef (0 :: Int) ; f i x where f i (Gate str r xs) = do val - readIORef r num - readIORef i case val of Nothing - do writeIORef r (Just num) writeIORef i (num+1) rest - mapM (f i) xs let is = map ((\(g,o,is) - o) . head) rest return ((str,num,is):concat rest) Just j - return [(indirection,j,[])] -- explicit sharing! Indirections can be filtered out at the end, they don't actually give the netlist any information. Of course, now that you have me reading up on Yhc.Core, option #5 is looking considerably more fun. Yeah, I think Yhc.Core is pretty nifty too. Thank Neil! Matt. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] I love purity, but it's killing me.
Hi Tom, In addition to the sharing problem, another shortcoming of Haskell DSLs is they can not fully exploit the benefits of algebraic datatypes. Specifically, pattern matching ADTs can only be used to control the compile-time configuration of the target, it can't be used to describe the target's behavior -- at least for DSLs that generate code that executes outside of Haskell's runtime. you can embed algebraic data types and pattern matching in Haskell with your own semantics, and retain type inference. It goes something like this: (nil, (|)) = datatype (cons0 [] \/ cons2 (:)) map f xs = match xs rules where rules (x, xs) = [ nil -- nil , x | xs -- f x | map f xs ] here, map :: (Term a - Term b) - Term [a] - Term [b]. The main issue is that you have to quantify the free variables in patterns, hence the rules function. I don't know if this helps you. Writing a real compiler would solve both of these problems. Is there any Haskell implementation that has a clean cut-point, from which I can start from a fully type-checked, type-annotated intermediate representation? The Yhc.Core library is very simple to use and fairly mature (Neil's been tweeking it for about 3 years now), but it doesn't meet your type-annotated requirement. (Untyped core is still pretty useful, though.) If you go the real compiler route, would it not make sense to take the DSL as the source language rather than Haskell? Or are the DSL and Haskell quite similar? Or perhaps you are thinking of a two language system, where some code is evaluated at compile time by Haskell, and some is compiled to the target language? If so, maybe you just want domain specific syntax inside a Haskell program, in which case the paper Why it's nice to be quoted: quasiquoting for haskell might be relevant (it's actually supported in GHC I think). Anyway, all very thought provoking! Matt. P.S. Tom Hawkins wrote: Emil Axelsson wrote: I know of a few of ways to express sharing in a pure language: 1) Observable sharing, which, in general, is unsafe. 2) Using Template Haskell 3) Matthew Naylor has done some work on expressible sharing, which has 4) Use a monad (but I'm sure this is what you're trying to avoid). Or... 5) Forget embedding the DSL, and write a direct compiler. Taking options 2 or 5 just to solve the sharing problem sounds to me like a lot of hard work for little reward. But don't worry, I won't repeat my observable sharing speech. :-) ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] I love purity, but it's killing me.
Hi, (Warning: longish message!) There is some concern, and rightly so, that observable sharing is dangerous, and that your Haskell program will explode if you use it, and perhaps even that anyone who uses it is dirty and should be sent to matron's for a good scrubbing! However, when used safely, it is not a hack, nor even dirty, but a nice, simple solution to an otherwise nasty problem. Below I define what I mean by safely. First consider the circumstances under which obserevable sharing is useful. Typically we have some Haskell function f that produces a symbolic representation of an expression. For whatever reason, we'd like to *generate a program* that computes the value of this expression, rather that computing it in Haskell. For example, in Lava, we want to generate a VHDL program so that the expression can be computed on, say, an FPGA. In Tom's case, he wants to generate a C program to compute the expression. All perfectly reasonable, and in my opinion, a very powerfull way to use Haskell. Now recall that referential transparency lets you replace equals with equals without changing the *value produced* by a program. Note that it says nothing about preserving *runtime behaviour*. Sharing, for example, may be lost. So if you do equational reasoning on function f (above), and loose some sharing, then you can only expect that the same sharing will also be also lost in the generated program. As long as the generated program computes the same result as it did before, referential transparency will be, overall, preserved; it would only be lost intermediately. This is what I mean by safe. Now, there remains the concern that Haskell's semantics does not enforce sharing. A Haskell compiler is free to change the sharing a program at a whim, unknowingly to the programmer who may be relying on it in for an efficient program. However, to my knowledge, it is an unwritten rule of Haskell compilers that sharing *is* preserved, and that they do perform *graph* reduction. Clean, a similar language to Haskell, indeed has a semantics based on graphs. So I don't believe Haskell being non-strict (not necessarily lazy) is a good reason for not using observable sharing. Though I do feel better when I compile without -O. :-) Finally, when I say observable sharing, I don't necessarily mean it as defined by Koen Claessen and David Sands. I simply mean the use of unsafePerformIO to detect sharing, whether or not this is done by an eq predicate on Refs. (I say this because I think there are simpler ways to detect sharing, though these will probably not have the nice semantic properties of observable sharing.) Sorry for the somewhat long exposition. :-) Matt. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
ghc -O
Hello GHC gurus, specifying -O or -O2 to GHC enables various optimisations to the frontend of the compiler, but I wonder does it turn on any optimistions to the backend/code-generator that are independent of the frontend? I can imagine that knowledge such as strictness which is computed by frontend would enable optimisations in the backend, but I'm more interested in whether the backend would do anything independent (e.g. peephole optimistion, C compiler options) with -O but not without. Thanks, Matt. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
[Haskell] ANNOUNCE: Lazy SmallCheck 0.1
Announcing Lazy SmallCheck 0.1, a library for exhaustive, demand-driven testing of Haskell programs. Lazy SmallCheck is based on the idea that if a property holds for a partially-defined input then it must also hold for all fully-defined instantiations of that input. Compared to `eager' input generation in SmallCheck, Lazy SmallCheck may require significantly fewer test-cases to verify a property for all inputs up to a given depth. There is a webpage for Lazy SmallCheck: http://www-users.cs.york.ac.uk/~mfn/lazysmallcheck/ There you'll find a more detailed description, a worked example, a comparison with SmallCheck on a number of benchmarks, and link to download the library. The library was developed together with Fredrik Lindblad during his recent visits to York. Suggestions, experiences and bug reports are welcome! Matthew. ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
[Haskell] ANNOUNCE: SparseCheck
Dear Haskellers, You might be interested in SparseCheck, a library for typed, depth-bounded logic programming in Haskell allowing convenient expression of test-data generators for properties with sparse domains. http://www.cs.york.ac.uk/~mfn/sparsecheck/ SparseCheck is a based on a library called LP (to be presented at the Haskell Workshop) that was developed jointly with Emil Axelsson. Matthew. ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
[Haskell] ANNOUNCE: The Reduceron
Dear Haskellers, You may be interested in the Reduceron: http://www-users.cs.york.ac.uk/~mfn/reduceron/index.html Here is a flavour: The Reduceron is a processor for executing Haskell programs on FPGA with the aim of exploring how custom architectural features can improve the speed in which Haskell functions are evaluated. Being described entirely in Haskell (using Lava), the Reduceron also serves as an interesting application of functional languages to the design of complex control circuits such as processors. To program the Reduceron we provide a basic Haskell compiler, called Tred, that translates Yhc.Core programs into codes of the Reduceron's instruction set. The Tred compiler and Reduceron processor are in the early stages of development: they are both fairly naive, inefficient, and lacking in many important features. But they represent a good start, already capable of correctly compiling and executing (on FPGA) a reasonable range of Haskell programs. See webpage for more details. Matthew. ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell-cafe] ANNOUNCE: nobench: Haskell implementaion benchmarks. GHC v Hugs v Yhc v NHC v ...
Hi all, GHC v Hugs v Yhc v NHC v ... ...Hacle Clean! I shoved 5 of the benchmarks that Donald used through Hacle, and compiled the outputs using version 2.1 of the Clean compiler. Results are below. As for the other examples, Hacle doesn't like non-Haskell98 and translates arbitrary-precision integers to fixed-precision ones (!) I'm not sure how well Hacle would work with nobench because input files must be unambiguously-typed assuming a default () at the top. So some programs may require a little tweaking to go through. Mind, this was only a problem on 1 of the 5 programs I just tried... Matt. (Note: ignore the 65536 at the end of each Clean result -- my fault for not compiling with the right options) === binarytrees (GHC) === stretch tree of depth 17 check: -1 131072 trees of depth 4check: -131072 32768trees of depth 6check: -32768 8192 trees of depth 8check: -8192 2048 trees of depth 10 check: -2048 512 trees of depth 12 check: -512 128 trees of depth 14 check: -128 32 trees of depth 16 check: -32 long lived tree of depth 16 check: -1 real0m3.301s user0m3.280s sys 0m0.016s === binarytrees (Clean) === Execution: 2.34 Garbage collection: 0.25 Total: 2.59 stretch tree of depth 17 check: -1 131072 trees of depth 4check: -131072 32768trees of depth 6check: -32768 8192 trees of depth 8check: -8192 2048 trees of depth 10 check: -2048 512 trees of depth 12 check: -512 128 trees of depth 14 check: -128 32 trees of depth 16 check: -32 long lived tree of depth 16 check: -1 65536 real0m2.691s user0m2.592s sys 0m0.100s === partial sums (GHC) === 2.9987 (2/3)^k 3160.817621887086 k^-0.5 0.99602026 1/k(k+1) 30.31454150956248 Flint Hills 42.99523399808393 Cookson Hills 15.30901715473893 Harmonic 1.644933666848388 Riemann Zeta 0.6931469805600944 Alternating Harmonic 0.7853980633974358 Gregory real0m4.887s user0m4.888s sys 0m0.000s === partial sums (Clean) === Execution: 4.41 Garbage collection: 0.05 Total: 4.46 3 (2/3)^k 3160.81762188709k^-0.5 0.9960203 1/k(k+1) 30.3145415095625Flint Hills 42.9952339980839Cookson Hills 15.3090171547389Harmonic 1.64493366684839Riemann Zeta 0.693146980560094 Alternating Harmonic 0.785398063397435 Gregory 65536 real0m4.545s user0m4.468s sys 0m0.076s === queens (GHC) === 14200 real0m1.990s user0m1.980s sys 0m0.012s === queens (Clean) === Execution: 6.58 Garbage collection: 1.07 Total: 7.65 14200 65536 real0m7.921s user0m7.656s sys 0m0.264s === recursive (GHC) === Ack(3,9): 4093 Fib(36.0): 2.4157817e7 Tak(24,16,8): 9 Fib(3): 3 Tak(3.0,2.0,1.0): 2.0 real0m5.232s user0m5.224s sys 0m0.008s === recursive (Clean) === Execution: 2.40 Garbage collection: 0.00 Total: 2.40 Ack(3,9): 4093 Fib(36): 24157817 Tak(24,16,8): 9 Fib(3): 3 Tak(3,2,1): 2 65536 real0m2.403s user0m2.400s sys 0m0.000s === loop (GHC) === 3.3335 real0m1.039s user0m1.036s sys 0m0.004s === loop (Clean) === Execution: 1.26 Garbage collection: 0.00 Total: 1.26 3.33 65536 real0m1.325s user0m1.260s sys 0m0.068s ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell] [ANNOUNCE] Hacle
Dear Haskellers and Cleaners, You may be interested in the results of my final-year student project at the University of York. It involved the development of a translator from Haskell to Clean; an idea that probably won't be too unfamiliar to most of you. The project's homepage is: http://www.cs.york.ac.uk/~mfn/hacle/ I hope that you enjoy the read, and find the results of interest. Kind regards. -- Matthew ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell