From la@iki.fi Mon Jun 2 00:52:55 2003 From: la@iki.fi (Lauri Alanko) Date: Mon, 2 Jun 2003 02:52:55 +0300 Subject: Eval in Haskell In-Reply-To: <200306012316.h51NGaai009292@adric.fnmoc.navy.mil> References: <20030531074837.GA6291@students.mimuw.edu.pl> <200305310257.h4V2vvxw003261@adric.fnmoc.navy.mil> <200306012316.h51NGaai009292@adric.fnmoc.navy.mil> Message-ID: <20030601235255.GA4498@la.iki.fi> [Moving to cafe, this is only barely Haskell-related.] On Sun, Jun 01, 2003 at 04:16:36PM -0700, oleg@pobox.com wrote: > Eval of the kind > let x = 1 in eval "x" > is plainly an abomination. I agree, though not because of the optimization issues but rather as a matter of principle: a closed variable should be _closed_, it should not be visible to anything but the body of the let-expression that binds it. And an externally acquired eval-able expression is definitely "anything but". Nevertheless, this abomination is supported even by some scheme implementations: guile> (define local-environment (procedure->syntax (lambda (exp env) env))) guile> (define (eval-where-x-bound exp) ... (let ((x 'foo)) (local-eval exp (local-environment)))) guile> (eval-where-x-bound '(list 'x x)) (x foo) > Incidentally, restricting eval to top-level or "standard" bindings is > not a significant limitation. It is, in general, a very good practice > to apply eval to closed expressions only. This depends entirely on what you want to achive with eval, so I don't think the "in general" is justified. If you just want to evaluate closed expressions whose results are printable and readable, then you really just have an embedded interpreter which happens to read the same language as your source code. On the other hand, it is common for perl programs and especially shell scripts to eval configuration files with the explicit purpose that the configuration file may alter variables which are bound in the main program. For such usage, it is essential that the main program and the evaled file access the same enviroment. (Naturally a configuration file shouldn't be allowed to mess with _everything_ in the main program, but I don't think perl allows detailed adjustment of the bindings in the environment. Some schemes do, though.) Lauri Alanko la@iki.fi From ashley@semantic.org Mon Jun 2 04:43:03 2003 From: ashley@semantic.org (Ashley Yakeley) Date: Sun, 01 Jun 2003 20:43:03 -0700 Subject: Eval in Haskell References: <20030531074837.GA6291@students.mimuw.edu.pl> <200305310257.h4V2vvxw003261@adric.fnmoc.navy.mil> <200306012316.h51NGaai009292@adric.fnmoc.navy.mil> <20030601235255.GA4498@la.iki.fi> Message-ID: In article <20030601235255.GA4498@la.iki.fi>, Lauri Alanko wrote: > Nevertheless, this abomination is supported even by some scheme > implementations: > > guile> (define local-environment (procedure->syntax (lambda (exp env) env))) > guile> (define (eval-where-x-bound exp) > ... (let ((x 'foo)) (local-eval exp (local-environment)))) > guile> (eval-where-x-bound '(list 'x x)) > (x foo) Guile seems to be a bit "sloppy" in general. I think it just keeps a dictionary of symbol bindings and passes it around at runtime. guile> (eval '(define b 5)) guile> b 5 -- Ashley Yakeley, Seattle WA From pdejuan@ucu.edu.uy Mon Jun 2 00:07:34 2003 From: pdejuan@ucu.edu.uy (Pablo Dejuan) Date: Mon, 02 Jun 2003 01:07:34 +0200 Subject: Is my question bad ? In-Reply-To: References: <000701c323d2$35155280$cea70950@p6t2x8> <000d01c32768$037b4c40$8e12f9c1@p6t2x8> Message-ID: <3EDA8736.3070407@ucu.edu.uy> Karl M Syring wrote:
Antoine Utonium wrote on Sat, 31 May 2003 13:29:09 +0200:
  
I recently asked you who knows how to link haskell-made code to C apps, or
call haskell code from C code, or encapsulate, traduce, Haskell code in C
code.
I just want to use haskell when I need advanced algorithms, & C for I/O, and
GUI (under windows)..
If my question has been answered yet, or if my english is too bad, please
say me, or give me links to answers.
Thanks.

Antoine Utonium wrote:
    
Everything is in the title. I like "simplicity" of Haskell and would
like to use what i write in my c/c++ programs.
Thanks a lot by advance.
      

I guess, there are people who have tried, but failed :-)
The easiest way would be to make a COM server in Haskell.
You should have a look at the HDirect sources, where there are
some examples. Generally using a COM dll from Haskell seems to
work, while the other way round seems to be problematic.

Karl M. Syring
  
If you are using GHC, you could compile your ".hs" to a Haskell C (".hc") which is a C file, this way:
          ghc -C myfile.hs

There are also other options like compiling an ".o" but I've never tried'em. Wish you luck.

From pocky6@yahoo.fr Mon Jun 2 06:24:41 2003 From: pocky6@yahoo.fr (Antoine Utonium) Date: Mon, 2 Jun 2003 07:24:41 +0200 Subject: Is my question bad ? References: <000701c323d2$35155280$cea70950@p6t2x8> <000d01c32768$037b4c40$8e12f9c1@p6t2x8> Message-ID: <000d01c328c7$50511580$c2a50950@p6t2x8> Karl M Syring wrote: > Antoine Utonium wrote on Sat, 31 May 2003 13:29:09 +0200: >> I recently asked you who knows how to link haskell-made code to C >> apps, or call haskell code from C code, or encapsulate, traduce, >> Haskell code in C code. >> I just want to use haskell when I need advanced algorithms, & C for >> I/O, and GUI (under windows).. >> If my question has been answered yet, or if my english is too bad, >> please say me, or give me links to answers. >> Thanks. >> >> Antoine Utonium wrote: >>> Everything is in the title. I like "simplicity" of Haskell and would >>> like to use what i write in my c/c++ programs. >>> Thanks a lot by advance. > > I guess, there are people who have tried, but failed :-) > The easiest way would be to make a COM server in Haskell. > You should have a look at the HDirect sources, where there are > some examples. Generally using a COM dll from Haskell seems to > work, while the other way round seems to be problematic. Thank you for your answer. I don't really know what is a COM server but msdn doc probably will say me more on that. I saw a work at microsoft research, called Pan, which used Haskell code, and translated it to C to compile it. But produced code was too obfusquated to reuse it in C sources. So i'm going to try COM solution. From la@iki.fi Mon Jun 2 06:57:26 2003 From: la@iki.fi (Lauri Alanko) Date: Mon, 2 Jun 2003 08:57:26 +0300 Subject: Eval in Haskell In-Reply-To: References: <20030531074837.GA6291@students.mimuw.edu.pl> <200305310257.h4V2vvxw003261@adric.fnmoc.navy.mil> <200306012316.h51NGaai009292@adric.fnmoc.navy.mil> <20030601235255.GA4498@la.iki.fi> Message-ID: <20030602055726.GA674@la.iki.fi> [We now have lost all pretence of topicality] On Sun, Jun 01, 2003 at 08:43:03PM -0700, Ashley Yakeley wrote: > Guile seems to be a bit "sloppy" in general. I think it just keeps a > dictionary of symbol bindings and passes it around at runtime. > > guile> (eval '(define b 5)) > guile> b > 5 This particular kind of sloppiness is pretty common in Scheme REPLs: la:~$ kawa #|kawa:1|# (eval '(define b 5)) #|kawa:2|# b 5 #|kawa:3|# la:~$ mzscheme Welcome to MzScheme version 204, Copyright (c) 1995-2003 PLT > (eval '(define b 5)) > b 5 > la:~$ bigloo ------------------------------------------------------------------------------ Bigloo (2.5c) ,--^, `a practical Scheme compiler' _ ___/ /|/ Wed Nov 27 10:49:16 CET 2002 ,;'( )__, ) ' Manuel Serrano ;; // L__. email: ' \ / ' Manuel.Serrano@sophia.inria.fr ^ ^ ------------------------------------------------------------------------------ Welcome to the interpreter 1:=> (eval '(define b 5)) b 1:=> b 5 1:=> la:~$ mit-scheme Scheme Microcode Version 14.9 MIT Scheme running under GNU/Linux Type `^C' (control-C) followed by `H' to obtain information about interrupts. Scheme saved on Tuesday June 18, 2002 at 2:26:05 AM Release 7.7.1 Microcode 14.9 Runtime 15.1 SF 4.40 Liar (Intel i386) 4.115 Edwin 3.112 1 ]=> (eval '(define b 5) system-global-environment) ;Value: b 1 ]=> b ;Value: 5 1 ]=> End of input stream reached Happy Happy Joy Joy. ... though admittedly it's a bit confusing, since "define" either binds or assigns to a variable, depending on whether it was already bound. Lauri Alanko la@iki.fi From Alistair_Bayley@ldn.invesco.com Mon Jun 2 08:58:07 2003 From: Alistair_Bayley@ldn.invesco.com (Bayley, Alistair) Date: Mon, 2 Jun 2003 08:58:07 +0100 Subject: Help: writing ffi bindings to a C library Message-ID: <7DFF3BC6CA957441AEADA7F340BFAA340C2EA7@GBLONEX11.lon.invesco.com> Yes, I had considered this (writing an abstraction layer in C). I have decided initially to try doing it in Haskell, because I thought that Haskell would be a better choice for writing abstraction layers (not as verbose as C). The idea was to write the Haskell-C bindings at as low a level as possible (i.e. directly to the OCI libraries), and then build up from there. Although the bindings may be ugly, I thought it would have been easier to build higher layers in Haskell rather than C. However, if you think it's probably better to build the first layer in C, then I'll do that. Getting back to my question, can I use functions that take twice-deref'ed pointers as args? This is a function that effectively returns some of its work in "out" arguments e.g. a C function like this: int someCFunction(SomeType **ptrptr, int i) (It would create an opaque structure and point *ptrptr at it. If it fails then it would return a negative value.) Is it simply a case of declaring it like this (in ghc): > data SomeType > type SomeTypeRef = Ptr SomeType > foreign import ccall "blah.h someCFunction" someCFunction :: Ptr SomeTypeRef -> Int -> Int Or must C functions that are to be called from Haskell return results only in the return value? -----Original Message----- From: Ronald Legere [mailto:rjljr2@yahoo.com] Sent: 31 May 2003 15:25 To: Bayley, Alistair; 'haskell-cafe@haskell.org' Subject: RE: Help: writing ffi bindings to a C library One strategy is to wrap that funtion in another function (in C) that encapsulates the 'typical' call you want to make. THen import this function into haskell. In any event, start with something simpler, to get the hang of it. Try to write a function (in C) that adds two integers,or prints something and import that in to haskell. There are some examples floating around to get you started, but I can't find them at the moment on the CVS tree. Anyone? Also, read "Tackling the awkward squad" (Google it) Ron --- "Bayley, Alistair" wrote: > So... > > I'm still trying to write this Oracle OCI ffi > binding. Can anyone tell me > how to declare the Haskell type for this function: > > sword OCIEnvCreate (OCIEnv **envp, ub4 mode, dvoid > *ctxp, > dvoid *(*malocfp)(dvoid *ctxp, > size_t size), > dvoid *(*ralocfp)(dvoid *ctxp, > dvoid *memptr, size_t > newsize), > void (*mfreefp)(dvoid *ctxp, > dvoid *memptr), > size_t xtramem_sz, dvoid > **usrmempp); > > Note that when I use it, I'm passing 0 (NULL) into > almost all of the args, > so the usage in C is typically: > > rc = OCIEnvCreate(&envhp, OCI_DEFAULT, 0, 0, 0, 0, > 0, 0); > > i.e. I don't care about most of the args, so that > should make the Haskell > declaration simpler. Some of the arguments are > pointers to functions, for > example. > > What I can't figure out is how to declare the type > of the first arg. Is is > Ptr (Ptr OCIEnv) ? > > Here's what I have so far (not much, I know): > > > module Main where > > import Foreign > > import Foreign.C.Types > > import Foreign.C.String > > import Foreign.Ptr > > > data OCIEnv > > > foreign import ccall "oci.h OCIEnvCreate" > ociEnvCreate :: Ptr OCIEnv -> > Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int > ***************************************************************** The information in this email and in any attachments is confidential and intended solely for the attention and use of the named addressee(s). This information may be subject to legal professional or other privilege or may otherwise be protected by work product immunity or other legal rules. It must not be disclosed to any person without our authority. If you are not the intended recipient, or a person responsible for delivering it to the intended recipient, you are not authorised to and must not disclose, copy, distribute, or retain this message or any part of it. ***************************************************************** From alastair@reid-consulting-uk.ltd.uk Mon Jun 2 10:18:36 2003 From: alastair@reid-consulting-uk.ltd.uk (Alastair Reid) Date: Mon, 2 Jun 2003 10:18:36 +0100 Subject: Is my question bad ? In-Reply-To: <000d01c32768$037b4c40$8e12f9c1@p6t2x8> References: <000701c323d2$35155280$cea70950@p6t2x8> <000d01c32768$037b4c40$8e12f9c1@p6t2x8> Message-ID: <200306021018.36493.alastair@reid-consulting-uk.ltd.uk> On Saturday 31 May 2003 12:29 pm, Antoine Utonium wrote: > I recently asked you who knows how to link haskell-made code to C apps, or > call haskell code from C code, or encapsulate, traduce, Haskell code in C > code. > I just want to use haskell when I need advanced algorithms, & C for I/O, > and GUI (under windows).. If the library you want to use is already available under COM, I agree with Karl M Syring that Haskell->COM tools (i.e., H/Direct) are the way to go. If they are available as normal C libraries, I'd recommend using either the foreign function interface (ffi) http://www.cse.unsw.edu.au/~chak/haskell/ffi/ or one of the tools that sits atop the foreign function interface. There is a very preliminary and slightly dated overview of all the tools here: http://www.reid-consulting-uk.ltd.uk/docs/ffi.html The best place to ask for information is on the ffi mailing list (ffi@haskell.org). In general, the more specific your question, the better the answer is likely to be. http://www.haskell.org/pipermail/ffi/ Hope this helps. -- Alastair Reid From qrczak@knm.org.pl Mon Jun 2 10:45:43 2003 From: qrczak@knm.org.pl (Marcin 'Qrczak' Kowalczyk) Date: Mon, 2 Jun 2003 11:45:43 +0200 Subject: Help: writing ffi bindings to a C library In-Reply-To: <7DFF3BC6CA957441AEADA7F340BFAA340C2EA7@GBLONEX11.lon.invesco.com> References: <7DFF3BC6CA957441AEADA7F340BFAA340C2EA7@GBLONEX11.lon.invesco.com> Message-ID: <200306021145.44166.qrczak@knm.org.pl> Dnia pon 2. czerwca 2003 09:58, Bayley, Alistair napisał: > Yes, I had considered this (writing an abstraction layer in C). I have > decided initially to try doing it in Haskell, because I thought that > Haskell would be a better choice for writing abstraction layers (not as > verbose as C). You can write it in Haskell too and I would recommend that - unless the C library uses some passing convention Haskell cannot handle (e.g. passing structs by value, or having variable argument count, or relying heavily on macros). > Getting back to my question, can I use functions that take twice-deref'ed > pointers as args? This is a function that effectively returns some of its > work in "out" arguments Sure. You can use libraries documented in the Haskell FFI proposal. > e.g. a C function like this: > > int someCFunction(SomeType **ptrptr, int i) > > (It would create an opaque structure and point *ptrptr at it. If it fails > then it would return a negative value.) > > Is it simply a case of declaring it like this (in ghc): > > data SomeType > > type SomeTypeRef = Ptr SomeType > > foreign import ccall "blah.h someCFunction" someCFunction :: > > Ptr SomeTypeRef -> Int -> Int foreign import ccall "blah.h someCFunction" someCFunction :: Ptr SomeTypeRef -> CInt -> IO CInt haskellWrapper :: Int -> IO (Maybe SomeTypeRef) haskellWrapper arg = alloca $ \ptr -> do res <- someCFunction ptr (fromIntegral arg) if res < 0 then return Nothing else liftM Just (peek ptr) You can raise an IO error instead. You can wrap the result in a ForeignPtr if it should be finalized when it's garbage collected. You can use hsc2hs to access integer constants, enumeration values and structs from Haskell, or write C wrappers inline inside Haskell source (e.g. to turn macros into functions). -- __("< Marcin Kowalczyk \__/ qrczak@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/ From guido.naudts@just.fgov.be Mon Jun 2 12:29:52 2003 From: guido.naudts@just.fgov.be (Naudts, Guido) Date: Mon, 02 Jun 2003 13:29:52 +0200 Subject: a readFile problem Message-ID: <3EDB3530.A41AB041@just.fgov.be> This is a multi-part message in MIME format. --------------9A73C4A959E00C5D54034EEE Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Hallo, I have the following problem: my program asks the user for a command, when the command is executed a new command is asked (this is no problem ; an example is in the HUgs distribution namely Main.hs in the Prolog example. However one of the commands is: read filename i.e. read a file and display it. I do not succeed in implementing this. Could anyone give an example of: reading commands in a loop where one of the commands is the read command mentionned above. Or is it not possible in Haskell? I have already wated a lot of time on this, so if anyone gives me an answer I will be very gratefull. Greetings, --------------9A73C4A959E00C5D54034EEE Content-Type: text/x-vcard; charset=us-ascii; name="guido.naudts.vcf" Content-Transfer-Encoding: 7bit Content-Description: Card for Naudts, Guido Content-Disposition: attachment; filename="guido.naudts.vcf" begin:vcard n:Guido;Naudts, Guido tel;fax:02/538.01.80 tel;home:014/51.32.43 tel;work:02/542.76.01 x-mozilla-html:TRUE url:http://www.just.fgov.be org:Ministerie van Justitie;Algemene Diensten adr:;;Eversstraat 2-8;Brussel;;1000;Belgium version:2.1 email;internet:guido.naudts@just.fgov.be title:Informaticus x-mozilla-cpt:;-30680 fn:Naudts, Guido end:vcard --------------9A73C4A959E00C5D54034EEE-- From Keith.Wansbrough@cl.cam.ac.uk Mon Jun 2 15:38:04 2003 From: Keith.Wansbrough@cl.cam.ac.uk (Keith Wansbrough) Date: Mon, 02 Jun 2003 15:38:04 +0100 Subject: a readFile problem In-Reply-To: Your message of "Mon, 02 Jun 2003 13:29:52 +0200." <3EDB3530.A41AB041@just.fgov.be> Message-ID: > However one of the commands is: read filename > i.e. read a file and display it. > I do not succeed in implementing this. http://www.haskell.org/hawiki/ThatAnnoyingIoType http://www.haskell.org/hawiki/UsingIo are your friends. --KW 8-) -- Keith Wansbrough http://www.cl.cam.ac.uk/users/kw217/ University of Cambridge Computer Laboratory. From hdaume@ISI.EDU Mon Jun 2 16:57:49 2003 From: hdaume@ISI.EDU (Hal Daume III) Date: Mon, 2 Jun 2003 08:57:49 -0700 (PDT) Subject: a readFile problem In-Reply-To: <3EDB3530.A41AB041@just.fgov.be> Message-ID: It would probably be helpful if you were to post the code you have and explain what part isn't working. There's a function: readFile :: FilePath -> IO String (FilePath is just a String) which reads a file. This should be what you need to solve this exercise... - Hal -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume On Mon, 2 Jun 2003, Naudts, Guido wrote: > Hallo, > I have the following problem: > my program asks the user for a command, when the command is executed a > new command is asked (this is no problem ; an example is in the HUgs > distribution namely Main.hs in the Prolog example. > However one of the commands is: read filename > i.e. read a file and display it. > I do not succeed in implementing this. > Could anyone give an example of: reading commands in a loop where one of > the commands is the read command mentionned above. > Or is it not possible in Haskell? > I have already wated a lot of time on this, so if anyone gives me an > answer I will be very gratefull. > Greetings, From thomas_bevan@toll.com.au Tue Jun 3 08:25:27 2003 From: thomas_bevan@toll.com.au (Thomas L. Bevan) Date: Tue, 3 Jun 2003 17:25:27 +1000 Subject: Networking : PortNumber Message-ID: <200306031725.28532.thomas_bevan@toll.com.au> Hi, How can I take some input and convert this into a PortID ? I don't quite understand why the constructor PortNumber doesn't have the signature PortID = PortNumber Int | ... Instead it is PortID = PortNumber PortNumber where PortNumber is not a member of the Read class. Tom From thomas_bevan@toll.com.au Tue Jun 3 08:28:05 2003 From: thomas_bevan@toll.com.au (Thomas L. Bevan) Date: Tue, 3 Jun 2003 17:28:05 +1000 Subject: Networking : PortNumber In-Reply-To: <200306031725.28532.thomas_bevan@toll.com.au> References: <200306031725.28532.thomas_bevan@toll.com.au> Message-ID: <200306031728.05339.thomas_bevan@toll.com.au> Sorry, I've just worked it out. PortNumber is an instance of the class Enum so we can use toEnum :: Int -> a Tom On Tue, 3 Jun 2003 05:25 pm, Thomas L. Bevan wrote: > Hi, > > How can I take some input and convert this into a > PortID ? > I don't quite understand why the constructor > PortNumber doesn't have the signature > > PortID = PortNumber Int | ... > > Instead it is > > PortID = PortNumber PortNumber > > where PortNumber is not a member of the Read class. > > Tom > > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe From simonmar@microsoft.com Tue Jun 3 11:22:20 2003 From: simonmar@microsoft.com (Simon Marlow) Date: Tue, 3 Jun 2003 11:22:20 +0100 Subject: Networking : PortNumber Message-ID: <9584A4A864BD8548932F2F88EB30D1C60D259BAC@TVP-MSG-01.europe.corp.microsoft.com> =20 > Sorry, >=20 > I've just worked it out. >=20 > PortNumber is an instance of the class Enum > so we can use >=20 > toEnum :: Int -> a It's also an instance of the Integral class, which means you can just write integral constants of type PortNumber. eg. (80 :: PortNumber) is valid. Also, the universal integral conversion function 'fromIntegral' can be used for converting values of other integral types into PortNumbers (this is preferable to toEnum). Cheers, Simon From m.p.donadio@ieee.org Tue Jun 3 23:48:14 2003 From: m.p.donadio@ieee.org (Matthew Donadio) Date: Tue, 03 Jun 2003 18:48:14 -0400 Subject: FFI Help Message-ID: <1054680494.2082.17.camel@mxd120.radnor01.pa.comcast.net> Hi all, I am just starting to experiment with FFI, and am running into a problem. I was to create an FFI to the lgamma(3) found in many of the newer libm implementations. My code follows the sig. The lgamma function works. The gamma function core dumps (I am using ghc 5.04.3) on me. gdb reports a SIGSEGV in signgam(), but I'm not sure why. I believe that I need to use the monad because signgam is only valid after lgamma returns. Does anyone have an idea what I am doing wrong? Thanks. -- Matthew Donadio > module Gamma (gamma, lgamma) where > import System.IO.Unsafe > foreign import ccall "math.h lgamma" lgammaC :: Double -> IO Double > foreign import ccall "math.h signgam" signgamC :: IO Int > lgamma :: Double -> Double > lgamma x = unsafePerformIO $ lgammaC x > gamma :: Double -> Double > gamma x = unsafePerformIO $ gammaIO x > gammaIO :: Double -> IO Double > gammaIO x = do lg <- lgammaC x > s <- signgamC > return $ fromIntegral s * exp lg From djsavimbi@phantomemail.com Tue Jun 3 11:50:06 2003 From: djsavimbi@phantomemail.com (David Savimbi) Date: Tue, 3 Jun 2003 11:50:06 +0100 Subject: Please help me Message-ID: <20030603225747.4A397421F13@www.haskell.org> From=3A David Jonas Savimbi Johannesburg=2C South Africa Email=3A djsavimbi=40phantomemail=2Ecom June 3rd=2C 2003=2E Dear Sir=2C It is my humble pleasure to write you this letter irrespective of the fact that you do not know me=2E However=2C I got your name through your country business directory here in my search for a reliable and trustworthy person that can assist me confidently=2E My name is Mr=2EJohn Jonas Savimbi=2E I am the son of Late Dr=2E Jonas Savimbi from Angola=2E I am 29 years old and I have got two younger sisters of same blood=2E Our mother died almost a year ago=2E We are all fighting for political asylum in South Africa=2E We cannot find a home in Angola anymore because of the war that our late father fought with the government of Angola until he died in that war=2E The government of Angola is now mad at us because our late father also wanted to be president and caused the people to fight the war for him because he was the president of UNITA political movement of Angola=2E So now we are in South Africa and we are suffering too much because we don't have money and the government of South Africa will not give jobs to asylum seekers=2E I am much concerned about my younger sisters who are finding it very difficult to manage in the situation=2E But I know that we should not suffer this way=2E I know that I must not let my younger sisters get into trouble because of money=2E So after consideration I am hereby begging for your assistance to help me to recover the sum of USD $29 Million which is my inheritance from my late mother=2E My late mother had taken this money with her to Spain in a diplomatic metal box marked =28Precious Stones=29=2E Subsequently she lodged the metal box =28As precious Stones=29 with a Securities and Valuables Protection company in Spain=2E I am supposed to be the beneficiary in the event of her death=2E However=2C all effort I made to go Spain to claim was refused by the Spainish embassy=2E And this was while it was still possible for me to travel=2E Now I cannot travel anywhere anymore=2E So in the situation that we are facing now=2C I must find somebody who can go to the Spain on my behalf=2E I understand that I will have to transfer my beneficiary rights unto you=2E I am willing to do so in the hope that you are a God fearing person who will not abandon us after you have the money=2E So from the bottom of my heart I am giving you 20% of the all the money=2E Once we have enough to sustain us sufficiently=2C you may be come our fund manager and invest the rest wisely for us=2E If you will be kind to assist us=2C please inform me urgently=2E Kind regards to you and your family=2E Sincerely=2C David Jonas savimbi From djsavimbi@phantomemail.com Tue Jun 3 12:27:20 2003 From: djsavimbi@phantomemail.com (David Savimbi) Date: Tue, 3 Jun 2003 12:27:20 +0100 Subject: Please help me Message-ID: <20030603233500.84B1F421F0D@www.haskell.org> From=3A David Jonas Savimbi Johannesburg=2C South Africa Email=3A djsavimbi=40phantomemail=2Ecom June 3rd=2C 2003=2E Dear Sir=2C It is my humble pleasure to write you this letter irrespective of the fact that you do not know me=2E However=2C I got your name through your country business directory here in my search for a reliable and trustworthy person that can assist me confidently=2E My name is Mr=2EJohn Jonas Savimbi=2E I am the son of Late Dr=2E Jonas Savimbi from Angola=2E I am 29 years old and I have got two younger sisters of same blood=2E Our mother died almost a year ago=2E We are all fighting for political asylum in South Africa=2E We cannot find a home in Angola anymore because of the war that our late father fought with the government of Angola until he died in that war=2E The government of Angola is now mad at us because our late father also wanted to be president and caused the people to fight the war for him because he was the president of UNITA political movement of Angola=2E So now we are in South Africa and we are suffering too much because we don't have money and the government of South Africa will not give jobs to asylum seekers=2E I am much concerned about my younger sisters who are finding it very difficult to manage in the situation=2E But I know that we should not suffer this way=2E I know that I must not let my younger sisters get into trouble because of money=2E So after consideration I am hereby begging for your assistance to help me to recover the sum of USD $29 Million which is my inheritance from my late mother=2E My late mother had taken this money with her to Spain in a diplomatic metal box marked =28Precious Stones=29=2E Subsequently she lodged the metal box =28As precious Stones=29 with a Securities and Valuables Protection company in Spain=2E I am supposed to be the beneficiary in the event of her death=2E However=2C all effort I made to go Spain to claim was refused by the Spainish embassy=2E And this was while it was still possible for me to travel=2E Now I cannot travel anywhere anymore=2E So in the situation that we are facing now=2C I must find somebody who can go to the Spain on my behalf=2E I understand that I will have to transfer my beneficiary rights unto you=2E I am willing to do so in the hope that you are a God fearing person who will not abandon us after you have the money=2E So from the bottom of my heart I am giving you 20% of the all the money=2E Once we have enough to sustain us sufficiently=2C you may be come our fund manager and invest the rest wisely for us=2E If you will be kind to assist us=2C please inform me urgently=2E Kind regards to you and your family=2E Sincerely=2C David Jonas savimbi From thomas_bevan@toll.com.au Wed Jun 4 08:29:13 2003 From: thomas_bevan@toll.com.au (Thomas L. Bevan) Date: Wed, 4 Jun 2003 17:29:13 +1000 Subject: Network.CGI Message-ID: <200306041729.13300.thomas_bevan@toll.com.au> Can anyone point me to some documentation on the Network.CGI package? The wrapper fn is clear enough but I'm not sure what pwrapper is for or the nature of the contract in connectToCGIScript Tom From glynn.clements@virgin.net Wed Jun 4 08:32:24 2003 From: glynn.clements@virgin.net (Glynn Clements) Date: Wed, 4 Jun 2003 08:32:24 +0100 Subject: FFI Help In-Reply-To: <1054680494.2082.17.camel@mxd120.radnor01.pa.comcast.net> References: <1054680494.2082.17.camel@mxd120.radnor01.pa.comcast.net> Message-ID: <16093.41096.758303.350957@cerise.nosuchdomain.co.uk> Matthew Donadio wrote: > I am just starting to experiment with FFI, and am running into a > problem. I was to create an FFI to the lgamma(3) found in many of the > newer libm implementations. My code follows the sig. > > The lgamma function works. The gamma function core dumps (I am using > ghc 5.04.3) on me. gdb reports a SIGSEGV in signgam(), but I'm not sure > why. I believe that I need to use the monad because signgam is only > valid after lgamma returns. > > Does anyone have an idea what I am doing wrong? > > Thanks. > > -- > Matthew Donadio > > > module Gamma (gamma, lgamma) where > > > import System.IO.Unsafe > > > foreign import ccall "math.h lgamma" lgammaC :: Double -> IO Double > > foreign import ccall "math.h signgam" signgamC :: IO Int signgam is an "int" variable, but this assumes that it is a function of type "int signgam(void)". Write a C wrapper "int get_signgam(void) { return signgam; }" and import that. -- Glynn Clements From Malcolm.Wallace@cs.york.ac.uk Wed Jun 4 10:47:45 2003 From: Malcolm.Wallace@cs.york.ac.uk (Malcolm Wallace) Date: Wed, 4 Jun 2003 10:47:45 +0100 Subject: FFI Help In-Reply-To: <16093.41096.758303.350957@cerise.nosuchdomain.co.uk> References: <1054680494.2082.17.camel@mxd120.radnor01.pa.comcast.net> <16093.41096.758303.350957@cerise.nosuchdomain.co.uk> Message-ID: <20030604104745.1bb2417c.Malcolm.Wallace@cs.york.ac.uk> > > > foreign import ccall "math.h signgam" signgamC :: IO Int > > signgam is an "int" variable, but this assumes that it is a function > of type "int signgam(void)". > > Write a C wrapper "int get_signgam(void) { return signgam; }" and > import that. Or alternatively, foreign import the address of the int and read it directly with 'peek'. import Foreign ... foreign import ccall "math.h &signgam" signgamC :: Ptr Int32 ... gammaIO :: Double -> IO Double gammaIO x = do lg <- lgammaC x s <- peek signgamC return $ fromIntegral s * exp lg Regards, Malcolm From Alistair_Bayley@ldn.invesco.com Wed Jun 4 13:16:44 2003 From: Alistair_Bayley@ldn.invesco.com (Bayley, Alistair) Date: Wed, 4 Jun 2003 13:16:44 +0100 Subject: Help: writing ffi bindings to a C library Message-ID: <7DFF3BC6CA957441AEADA7F340BFAA340C2EBB@GBLONEX11.lon.invesco.com> Thanks. This is very helpful. I'm making much better progress now. Is alloca the idiomatic technique when you want to create a pointer to a pointer? Or are there other ways? Initially I tried to pass a Ptr (Ptr SomeType), but I couldn't because Ptr has no constructors To create values of type Ptr I must use the functions in Foreign.Marshal.Alloc (and Foreign.Marshal.Utils). Correct? -----Original Message----- From: Marcin 'Qrczak' Kowalczyk [mailto:qrczak@knm.org.pl] Sent: 02 June 2003 10:46 To: haskell-cafe@haskell.org Subject: Re: Help: writing ffi bindings to a C library Dnia pon 2. czerwca 2003 09:58, Bayley, Alistair napisa=B3: > Yes, I had considered this (writing an abstraction layer in C). I have > decided initially to try doing it in Haskell, because I thought that > Haskell would be a better choice for writing abstraction layers (not as > verbose as C). You can write it in Haskell too and I would recommend that - unless the C= library uses some passing convention Haskell cannot handle (e.g. passing= structs by value, or having variable argument count, or relying heavily on= macros). > Getting back to my question, can I use functions that take twice-deref'ed > pointers as args? This is a function that effectively returns some of its > work in "out" arguments Sure. You can use libraries documented in the Haskell FFI proposal. > e.g. a C function like this: > > int someCFunction(SomeType **ptrptr, int i) > > (It would create an opaque structure and point *ptrptr at it. If it fails > then it would return a negative value.) > > Is it simply a case of declaring it like this (in ghc): > > data SomeType > > type SomeTypeRef =3D Ptr SomeType > > foreign import ccall "blah.h someCFunction" someCFunction :: > > Ptr SomeTypeRef -> Int -> Int foreign import ccall "blah.h someCFunction" someCFunction :: Ptr SomeTypeRef -> CInt -> IO CInt haskellWrapper :: Int -> IO (Maybe SomeTypeRef) haskellWrapper arg =3D alloca $ \ptr -> do res <- someCFunction ptr (fromIntegral arg) if res < 0 then return Nothing else liftM Just (peek ptr) You can raise an IO error instead. You can wrap the result in a ForeignPtr if=20 it should be finalized when it's garbage collected. You can use hsc2hs to access integer constants, enumeration values and structs=20 from Haskell, or write C wrappers inline inside Haskell source (e.g. to turn macros into functions). --=20 __("< Marcin Kowalczyk \__/ qrczak@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/ _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe ***************************************************************** The information in this email and in any attachments is=20 confidential and intended solely for the attention and use=20 of the named addressee(s). This information may be=20 subject to legal professional or other privilege or may=20 otherwise be protected by work product immunity or other=20 legal rules. It must not be disclosed to any person without=20 our authority. If you are not the intended recipient, or a person=20 responsible for delivering it to the intended recipient, you=20 are not authorised to and must not disclose, copy,=20 distribute, or retain this message or any part of it. ***************************************************************** From gk@ninebynine.org Wed Jun 4 12:08:38 2003 From: gk@ninebynine.org (Graham Klyne) Date: Wed, 04 Jun 2003 12:08:38 +0100 Subject: powerset Message-ID: <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> A brief search of the libraries didn't reveal (top me) a ready-to-roll powerset function. I thought this may be a useful exercise to see how well I'm picking up on functional programming idioms, so I offer the following for comment: [[ -- |Powerset of a list, in ascending order of size. -- Assumes the supplied list has no duplicate elements. powerSet :: [a] -> [[a]] powerSet as = foldl (++) [] [ combinations n as | n <- intRange 1 (length as) ] -- |Combinations of n elements from a list, each being returned in the -- order that they appear in the list. combinations :: Int -> [a] -> [[a]] combinations _ [] = [] -- Don't include empty combinations combinations n as@(ah:at) | n <= 0 = [[]] | n > length as = [] | n == length as = [as] | otherwise = (map (ah:) $ combinations (n-1) at) ++ (combinations n at) -- |Return list of integers from lo to hi. intRange :: Int -> Int -> [Int] intRange lo hi = take (hi-lo+1) (iterate (+1) 1) -- Tests testcomb0 = combinations 0 "abcd" -- [] testcomb1 = combinations 1 "abcd" -- ["a","b","c","d"] testcomb2 = combinations 2 "abcd" -- ["ab","ac","ad","bc","bd","cd"] testcomb3 = combinations 3 "abcd" -- ["abc","abd","acd","bcd"] testcomb4 = combinations 4 "abcd" -- ["abcd"] testcomb5 = combinations 5 "abcd" -- [] testpower = powerSet "abc" -- ["a","b","c","ab","ac","bc","abc"] ]] I think the recursive use of 'combinations' may be inefficient, and could maybe be improved by "memoizing"? #g ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From Keith.Wansbrough@cl.cam.ac.uk Wed Jun 4 14:00:08 2003 From: Keith.Wansbrough@cl.cam.ac.uk (Keith Wansbrough) Date: Wed, 04 Jun 2003 14:00:08 +0100 Subject: powerset In-Reply-To: Your message of "Wed, 04 Jun 2003 12:08:38 BST." <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> Message-ID: > A brief search of the libraries didn't reveal (top me) a ready-to-roll > powerset function. > > I thought this may be a useful exercise to see how well I'm picking up on > functional programming idioms, so I offer the following for comment: [..] > I think the recursive use of 'combinations' may be inefficient, and could > maybe be improved by "memoizing"? Looks fine, but you're right - the use of "combinations" is inefficient. It's better to iterate over the elements, rather than the length. Then as you add each element, you consider all the sets you have so far, and either add the new element to each or not. This doubles the number of sets. Hence: powerset :: [a] -> [[a]] powerset [] = [[]] powerset (x:xs) = xss ++ map (x:) xss where xss = powerset xs Notice how important it is to include the empty set in the set of subsets - it won't work at all if you omit it. This formulation is particularly nice because in memory, you *share* all of the lists from the previous iteration, rather than making copies. After doing "powerset [1,2,3,4]", the heap looks something like this: let a = [] b = 1:a c = 2:a d = 2:b e = 3:a f = 3:b g = 3:c h = 3:d i = 4:a j = 4:b k = 4:c l = 4:d m = 4:e n = 4:f o = 4:g p = 4:h in [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p] Notice all the sharing - this is a very efficient representation! You save on copying, and you save on memory use. My solution isn't perfect, though - the use of append (++) is inefficient; if this could be avoided, it would be faster. --KW 8-) From liyang@nerv.cx Wed Jun 4 15:08:44 2003 From: liyang@nerv.cx (Liyang HU) Date: Wed, 4 Jun 2003 15:08:44 +0100 Subject: powerset In-Reply-To: <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> References: <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> Message-ID: <20030604140844.GB11206@boris.qub.ac.uk> Hi Graham, On Wed, Jun 04, 2003 at 12:08:38PM +0100, Graham Klyne wrote: > I thought this may be a useful exercise to see how well I'm picking up on > functional programming idioms, so I offer the following for comment: > foldl (++) [] [ combinations n as | n <- intRange 1 (length as) ] By your use of the `intRange' function, I get the feeling you're still thinking somewhat imperatively. (It's awfully reminiscent of a for-loop...) Were you trying to write the function from some definition? (The set of all subsets of X with size <= |X| et c. You're looping over the size of the subset, per se...?) (Side note: I can think of few instances where you _need_ to deal with the length of a list directly -- more often than not you can (and probably should) let recursion take care of that. You can also write [1..length as] rather than use the intRange function, which looks prettier. :-) A key point is to try and think of how you can relate one case of the problem to a simpler instance of the same problem, rather than tackling it head on. Start by looking at the power set of a few small examples. The power set of the empty set is the size 1 set consisting of the empty set: > pset [] = [ [] ] and a couple more: > pset [a] = [ [a], [] ] > pset [b, a] = [ [b, a], [b], [a], [] ] Notice how the `second half' of pset [b, a] is exactly pset [a]. Can you see anything that would relate the sets [b, a], [b] to [a], []? (Yes! Chop off the leading b! :) Let's try to generalise this: Take a set X, and an element y not in X. Denoting the power set function by P(), I hope you can see that P(X u {y}) certainly contains P(X). But no set in (read: member of) P(X) has y as a member, and funnily enough, if we add y to each element of P(X) we get missing bits of P(X u {y}). (The fact that the size of the power set is 2^|X| should serve as a hint -- you want to double the size of your power set for each element in X.) So we arrive at our solution: > pset [] = [ [] ] > pset (x:xs) = let ps = pset xs in map (x:) ps ++ ps Or at least, this is what would be going through my head if I were trying to write this. ^_^ Hope it helps a bit... later, /Liyang -- .--| Liyang HU |--| http://nerv.cx/ |--| Caius@Cam |--| ICQ: 39391385 |--. | :::::::::::::::::::::: This is not a signature. :::::::::::::::::::::: | From qrczak@knm.org.pl Wed Jun 4 15:33:41 2003 From: qrczak@knm.org.pl (Marcin 'Qrczak' Kowalczyk) Date: Wed, 4 Jun 2003 16:33:41 +0200 Subject: Help: writing ffi bindings to a C library In-Reply-To: <7DFF3BC6CA957441AEADA7F340BFAA340C2EBB@GBLONEX11.lon.invesco.com> References: <7DFF3BC6CA957441AEADA7F340BFAA340C2EBB@GBLONEX11.lon.invesco.com> Message-ID: <200306041633.41873.qrczak@knm.org.pl> Dnia śro 4. czerwca 2003 14:16, Bayley, Alistair napisał: > Is alloca the idiomatic technique when you want to create a pointer to a > pointer? Or are there other ways? It's an idiomatic technique for creating a temporary C object whose lifetime is explicit. You could use malloc, but then you have to remember to free it. alloca is an analogue of local variables in C (they are really allocated on GHC heap in GHC or with malloc in other implementations). > Initially I tried to pass a Ptr (Ptr SomeType), but I couldn't because Ptr > has no constructors To create values of type Ptr I must use the functions > in Foreign.Marshal.Alloc (and Foreign.Marshal.Utils). Correct? More or less yes (there is nullPtr, you can 'foreign import' pointers to global C variables, you can return pointers from imported C functions if it makes sense...). -- __("< Marcin Kowalczyk \__/ qrczak@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/ From Alistair_Bayley@ldn.invesco.com Wed Jun 4 16:16:40 2003 From: Alistair_Bayley@ldn.invesco.com (Bayley, Alistair) Date: Wed, 4 Jun 2003 16:16:40 +0100 Subject: How do I create an IOError exception? Message-ID: <7DFF3BC6CA957441AEADA7F340BFAA340C2EBF@GBLONEX11.lon.invesco.com> (I know I'm asking some noddy questions, but hey, that's what this list is for...) How do I create IOError exceptions? System.IO.Error has two functions that create IOErrors: userError and mkIOError. However, both of them take a String (I assume containing a description of the problem), and mkIOError takes optional Handle and FilePath args. http://www.haskell.org/ghc/docs/latest/html/base/System.IO.Error.html What I'd like to do is stuff some more information into the exception (a bit like Java exceptions), along the lines of: > mkIOError :: a -> IOError where I could choose to use it like this (ociHandleAlloc is a foreign C function): > handleAlloc2 handleType env ptr = do > rc <- ociHandleAlloc env ptr handleType 0 0 > if rc < 0 > then ioError (mkIOError ("Couldn't allocate handle", rc)) > else peek ptr When I catch the exception (currently in main) I would like to interrogate it to get the values I stuffed in it (in this case a (String, Int) tuple), and then do some error reporting by calling another function which decodes the error number. Is this the wrong way to go about error handling? Or is it relatively simple to create your own IOErrors? Have I missed something in the docs? ***************************************************************** The information in this email and in any attachments is confidential and intended solely for the attention and use of the named addressee(s). This information may be subject to legal professional or other privilege or may otherwise be protected by work product immunity or other legal rules. It must not be disclosed to any person without our authority. If you are not the intended recipient, or a person responsible for delivering it to the intended recipient, you are not authorised to and must not disclose, copy, distribute, or retain this message or any part of it. ***************************************************************** From hdaume@ISI.EDU Wed Jun 4 16:31:31 2003 From: hdaume@ISI.EDU (Hal Daume III) Date: Wed, 4 Jun 2003 08:31:31 -0700 (PDT) Subject: How do I create an IOError exception? In-Reply-To: <7DFF3BC6CA957441AEADA7F340BFAA340C2EBF@GBLONEX11.lon.invesco.com> Message-ID: In Control.Exception, there's: > data Exception = ... > | DynException Dynamic > | ... and > throwIO :: Exception -> IO a so, what you want is probably something like: > if rc < 0 > then throwIO (DynException (toDyn ("Err", rc))) > else ... and then when you catch, use fromDyn(amic) to get the value out if you can predict its type... HTH. - Hal -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume On Wed, 4 Jun 2003, Bayley, Alistair wrote: > (I know I'm asking some noddy questions, but hey, that's what this list is > for...) > > How do I create IOError exceptions? System.IO.Error has two functions that > create IOErrors: userError and mkIOError. However, both of them take a > String (I assume containing a description of the problem), and mkIOError > takes optional Handle and FilePath args. > > http://www.haskell.org/ghc/docs/latest/html/base/System.IO.Error.html > > What I'd like to do is stuff some more information into the exception (a bit > like Java exceptions), along the lines of: > > > mkIOError :: a -> IOError > > where I could choose to use it like this (ociHandleAlloc is a foreign C > function): > > > handleAlloc2 handleType env ptr = do > > rc <- ociHandleAlloc env ptr handleType 0 0 > > if rc < 0 > > then ioError (mkIOError ("Couldn't allocate handle", rc)) > > else peek ptr > > > When I catch the exception (currently in main) I would like to interrogate > it to get the values I stuffed in it (in this case a (String, Int) tuple), > and then do some error reporting by calling another function which decodes > the error number. > > Is this the wrong way to go about error handling? Or is it relatively simple > to create your own IOErrors? Have I missed something in the docs? > > > ***************************************************************** > The information in this email and in any attachments is > confidential and intended solely for the attention and use > of the named addressee(s). This information may be > subject to legal professional or other privilege or may > otherwise be protected by work product immunity or other > legal rules. It must not be disclosed to any person without > our authority. > > If you are not the intended recipient, or a person > responsible for delivering it to the intended recipient, you > are not authorised to and must not disclose, copy, > distribute, or retain this message or any part of it. > ***************************************************************** > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe > From m.p.donadio@ieee.org Wed Jun 4 21:33:17 2003 From: m.p.donadio@ieee.org (Matthew Donadio) Date: Wed, 04 Jun 2003 16:33:17 -0400 Subject: FFI Help References: <1054680494.2082.17.camel@mxd120.radnor01.pa.comcast.net> <16093.41096.758303.350957@cerise.nosuchdomain.co.uk> <20030604104745.1bb2417c.Malcolm.Wallace@cs.york.ac.uk> Message-ID: <3EDE578D.A6D20692@ieee.org> Malcolm Wallace wrote: > > > > foreign import ccall "math.h signgam" signgamC :: IO Int > > > > signgam is an "int" variable, but this assumes that it is a function > > of type "int signgam(void)". > > > > Write a C wrapper "int get_signgam(void) { return signgam; }" and > > import that. > > Or alternatively, foreign import the address of the int and read it > directly with 'peek'. Thanks for the clarification. I went with the second option, and that works great. -- Matthew Donadio (m.p.donadio@ieee.org) From GK@ninebynine.org Wed Jun 4 21:42:18 2003 From: GK@ninebynine.org (Graham Klyne) Date: Wed, 04 Jun 2003 21:42:18 +0100 Subject: powerset In-Reply-To: <20030604140844.GB11206@boris.qub.ac.uk> References: <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> Message-ID: <5.1.0.14.2.20030604214132.033fc090@127.0.0.1> At 15:08 04/06/03 +0100, Liyang HU wrote: >A key point is to try and think of how you can relate one case of the >problem to a simpler instance of the same problem, rather than tackling it >head on. I think that's a good idea to hang on to. Sometimes easier to say than to do, it seems. Thanks, #g ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From GK@ninebynine.org Wed Jun 4 21:04:35 2003 From: GK@ninebynine.org (Graham Klyne) Date: Wed, 04 Jun 2003 21:04:35 +0100 Subject: powerset In-Reply-To: References: Message-ID: <5.1.0.14.2.20030604192502.0305aa30@127.0.0.1> At 14:00 04/06/03 +0100, Keith Wansbrough wrote: >Looks fine, but you're right - the use of "combinations" is >inefficient. It's better to iterate over the elements, rather than >the length. Then as you add each element, you consider all the sets >you have so far, and either add the new element to each or not. This >doubles the number of sets. Hence: > >powerset :: [a] -> [[a]] >powerset [] = [[]] >powerset (x:xs) = xss ++ map (x:) xss > where xss = powerset xs Neat! It happens that for the application I have in mind, it is important to generate shorter subsets first, as the required results are almost always going to come from smaller subsets of a possibly large base set, and I'm aiming to exploit lazy evaluation to keep things tractable. Looking at your code, I'm wondering if it would be possible to use some alternate form of composition instead of ++, and some auxiliary functions to pull the results out in the short-to-long sequence. I'm thinking in terms of building a list of trees.. [[ data NTree a = NTree { nthead::a, ntbody::[NTree a] } instance Functor NTree where fmap f (NTree h ts) = NTree (f h) (map (fmap f) ts) powerset1 :: [a] -> [NTree [a]] powerset1 (x:xs) = (NTree [x] (map (fmap (x:)) xss)) : xss where xss = powerset1 xs powerset1 [] = [] listPowerset :: [NTree [a]] -> [[a]] listPowerset [] = [] listPowerset ts = (map nthead ts) ++ listPowerset bodylist where bodylist = concat $ filter (not . null) $ map ntbody ts testN1 = listPowerset $ powerset1 [1,2,3,4] testN2 = listPowerset $ powerset1 "abcdefgh" ]] The list/tree structure looks something like this: [1] [2] [2,1] [3] [3,1] [3,2] [3,2,1] [4] [4,1] [4,2] [4,2,1] [4,3] [4,3,1] [4,3,2] [4,3,2,1] etc. The list function picks off the members by columns (w.r.t. to above diag) >Notice how important it is to include the empty set in the set of >subsets - it won't work at all if you omit it. Yes, I noticed something similar in my original version. I've chosen not include the empty subset in my results, but that's easily adjusted. >This formulation is particularly nice because in memory, you *share* >all of the lists from the previous iteration, rather than making >copies. I *think* my revised formulation achieves this. [...] >My solution isn't perfect, though - the use of append (++) is >inefficient; if this could be avoided, it would be faster. I didn't see any easy way to avoid (++) in my list readout, but I think I can claim that the length of the leading list if never more than O(log N) the tree size. If I'm evaluating and using the list lazily, using a typical recursive traversal pattern (like the powerset function itself), is there any cause for the "++" to actually be evaluated? I suspect not, but can't be sure. #g ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From glynn.clements@virgin.net Wed Jun 4 21:29:51 2003 From: glynn.clements@virgin.net (Glynn Clements) Date: Wed, 4 Jun 2003 21:29:51 +0100 Subject: FFI Help In-Reply-To: <20030604104745.1bb2417c.Malcolm.Wallace@cs.york.ac.uk> References: <1054680494.2082.17.camel@mxd120.radnor01.pa.comcast.net> <16093.41096.758303.350957@cerise.nosuchdomain.co.uk> <20030604104745.1bb2417c.Malcolm.Wallace@cs.york.ac.uk> Message-ID: <16094.22207.500023.277902@cerise.nosuchdomain.co.uk> Malcolm Wallace wrote: > > > > foreign import ccall "math.h signgam" signgamC :: IO Int > > > > signgam is an "int" variable, but this assumes that it is a function > > of type "int signgam(void)". > > > > Write a C wrapper "int get_signgam(void) { return signgam; }" and > > import that. > > Or alternatively, foreign import the address of the int and read it > directly with 'peek'. > > import Foreign > ... > foreign import ccall "math.h &signgam" signgamC :: Ptr Int32 > ... > gammaIO :: Double -> IO Double > gammaIO x = do lg <- lgammaC x > s <- peek signgamC > return $ fromIntegral s * exp lg One potential drawback with that approach is that an implementation might decide to add thread-safety, in the same manner as glibc does with errno: # if !defined _LIBC || defined _LIBC_REENTRANT /* When using threads, errno is a per-thread value. */ # define errno (*__errno_location ()) # endif [where __errno_location() returns a thread-specific location via pthread_getspecific().] OTOH, a C wrapper will cope with whatever contortions the libc developers decide to use. -- Glynn Clements From ddarius@hotpop.com Thu Jun 5 00:50:01 2003 From: ddarius@hotpop.com (Derek Elkins) Date: Wed, 4 Jun 2003 19:50:01 -0400 Subject: powerset In-Reply-To: <20030604140844.GB11206@boris.qub.ac.uk> References: <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <20030604140844.GB11206@boris.qub.ac.uk> Message-ID: <20030604195001.00007769.ddarius@hotpop.com> On Wed, 4 Jun 2003 15:08:44 +0100 Liyang HU wrote: > Hi Graham, > > On Wed, Jun 04, 2003 at 12:08:38PM +0100, Graham Klyne wrote: > > I thought this may be a useful exercise to see how well I'm picking > > up on functional programming idioms, so I offer the following for > > comment: > > > foldl (++) [] [ combinations n as | n <- intRange 1 (length as) > > ] *cries out in pain and horror* fold_l_ (++) over combinatorially large lists! (++) has gotten a reputation for being slow. (++) isn't slow in and of itself, even using it a lot isn't slow, what -is- slow is using it left associatively. What happens then is that (a++b)++c builds a copy of a then tacks on b, then it builds a copy of a++b and tacks on c. In this case we've copied a twice when we should have only copied it once. Obviously for ((a++b)++c)++d it'll be copied three times and b twice and so forth. To add insult to injury, there is already a standard function that does what you want, concat, which is defined as foldr (++) [] in the report. In fact, you could rewrite the whole thing as concatMap (flip combinations as) [1..length as]. A list comprehension with only one source and no filters is the same as a map. > By your use of the `intRange' function, I get the feeling you're still > thinking somewhat imperatively. (It's awfully reminiscent of a > for-loop...) Were you trying to write the function from some > definition? (The set of all subsets of X with size <= |X| et c. You're > looping over the size of the subset, per se...?) > > (Side note: I can think of few instances where you _need_ to deal with > the length of a list directly -- more often than not you can (and > probably should) let recursion take care of that. You can also write > [1..length as] rather than use the intRange function, which looks > prettier. :-) Indeed, I think I've used length all of 3 times. You (Graham) also have some parentheses issues; e.g. in foo ++ (combinations 5 l) the parentheses are superfluous. (++) is slow though in that seemingly innocent uses can become n^2. A simple example is displaying a binary tree. A tree like /\ /\ will cause left associative uses of (++). Hence the prelude type ShowS = String -> String and shows :: Show a => a -> ShowS. The problem is we don't want left associativity, so what we do is make a context that says do everything else to the right, then this, e.g. "Foo"++everythingelse. This is simple enough to do with ("Foo"++). (As a side note, using the Writer/Output monad with the list/string monoid is probably not the best of ideas, instead you can use the function monoid and tell ("foo"++).) You can see that this technique is more or less just adding an accumulating parameter as you'll have to provide the 'initial' value. From ajb@spamcop.net Thu Jun 5 05:53:18 2003 From: ajb@spamcop.net (Andrew J Bromage) Date: Thu, 5 Jun 2003 14:53:18 +1000 Subject: powerset In-Reply-To: References: <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> Message-ID: <20030605045318.GA18446@smtp.alicorna.com> G'day all. On Wed, Jun 04, 2003 at 02:00:08PM +0100, Keith Wansbrough wrote: > This formulation is particularly nice because in memory, you *share* > all of the lists from the previous iteration, rather than making > copies. [...] > Notice all the sharing - this is a very efficient representation! You > save on copying, and you save on memory use. I can never resist a can labelled "worms". Let me get out my tin opener... You do save on memory allocations. If, however, you consume the list lazily and discard the results as you consume them (which is the common way lazy programs are written), you actually use more memory at once. Try it if you don't believe me. Test it with this program, using each definition of powerset: summer :: [[a]] -> Integer summer xss = foldl' (\xs r -> r + toInteger (length xs)) 0 xss n :: Int n = 32 main :: IO () main = print (summer (powerset [1..n])) You'll find that one of them runs in O(n) space and the other most likely blows the heap. Cheers, Andrew Bromage From Alistair_Bayley@ldn.invesco.com Thu Jun 5 08:02:09 2003 From: Alistair_Bayley@ldn.invesco.com (Bayley, Alistair) Date: Thu, 5 Jun 2003 08:02:09 +0100 Subject: How do I create an IOError exception? Message-ID: <7DFF3BC6CA957441AEADA7F340BFAA340C2EC0@GBLONEX11.lon.invesco.com> Ahh... I see now (thanks). This advice (in the documentation for System.IO.Error.ioError) threw me: "The ioError variant should be used in preference to throw to raise an exception within the IO monad because it guarantees ordering with respect to other IO operations, whereas throw does not." After reading this I assumed that I should also use the exceptions in System.IO.Error i.e. the IOError type. But of course this is not the case; ioError has type Exception -> IO a. -----Original Message----- From: Hal Daume III [mailto:hdaume@ISI.EDU] Sent: 04 June 2003 16:32 To: Bayley, Alistair Cc: haskell-cafe@haskell.org Subject: Re: How do I create an IOError exception? In Control.Exception, there's: > data Exception = ... > | DynException Dynamic > | ... and > throwIO :: Exception -> IO a so, what you want is probably something like: > if rc < 0 > then throwIO (DynException (toDyn ("Err", rc))) > else ... and then when you catch, use fromDyn(amic) to get the value out if you can predict its type... HTH. - Hal -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume On Wed, 4 Jun 2003, Bayley, Alistair wrote: > (I know I'm asking some noddy questions, but hey, that's what this list is > for...) > > How do I create IOError exceptions? System.IO.Error has two functions that > create IOErrors: userError and mkIOError. However, both of them take a > String (I assume containing a description of the problem), and mkIOError > takes optional Handle and FilePath args. > > http://www.haskell.org/ghc/docs/latest/html/base/System.IO.Error.html > > What I'd like to do is stuff some more information into the exception (a bit > like Java exceptions), along the lines of: > > > mkIOError :: a -> IOError > > where I could choose to use it like this (ociHandleAlloc is a foreign C > function): > > > handleAlloc2 handleType env ptr = do > > rc <- ociHandleAlloc env ptr handleType 0 0 > > if rc < 0 > > then ioError (mkIOError ("Couldn't allocate handle", rc)) > > else peek ptr > > > When I catch the exception (currently in main) I would like to interrogate > it to get the values I stuffed in it (in this case a (String, Int) tuple), > and then do some error reporting by calling another function which decodes > the error number. > > Is this the wrong way to go about error handling? Or is it relatively simple > to create your own IOErrors? Have I missed something in the docs? > ***************************************************************** The information in this email and in any attachments is confidential and intended solely for the attention and use of the named addressee(s). This information may be subject to legal professional or other privilege or may otherwise be protected by work product immunity or other legal rules. It must not be disclosed to any person without our authority. If you are not the intended recipient, or a person responsible for delivering it to the intended recipient, you are not authorised to and must not disclose, copy, distribute, or retain this message or any part of it. ***************************************************************** From karczma@info.unicaen.fr Thu Jun 5 10:06:24 2003 From: karczma@info.unicaen.fr (Jerzy Karczmarczuk) Date: Thu, 05 Jun 2003 11:06:24 +0200 Subject: powerset References: <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604214132.033fc090@127.0.0.1> Message-ID: <3EDF0810.1040701@info.unicaen.fr> Graham Klyne wrote: > At 15:08 04/06/03 +0100, Liyang HU wrote: > >> A key point is to try and think of how you can relate one case of the >> problem to a simpler instance of the same problem, rather than >> tackling it >> head on. > > > I think that's a good idea to hang on to. Sometimes easier to say than > to do, it seems. I permit myself to observe that your powerset problem (and the restricted length problem, i.e. the combinations) is usually solved in Prolog, through backtracking, using reasoning/style which adopts this "individualistic" philosophy. powerset(,) --- is the pattern. And the solution is powerset([],[]). Since nothing else can be done. Otherwise you pick the item or not. powerset([X|Rest],L) :- powerset(Rest,L). powerset([X|Rest],[X|L) :- powerset(Rest,L). The xxx ++ map (x :) xxx solution in Haskell is a particular formulation (and optimization) of the straightforward transformation from a version using the non-deterministic Monad. This one is really almost a carbon copy of the Prolog solution, with appropriate "lifting" of operations from individuals to lazy lists. Such things are sometimes easier to do than to describe... Jerzy Karczmarczuk From jack.stecher@retek.com Thu Jun 5 14:09:02 2003 From: jack.stecher@retek.com (Stecher, Jack) Date: Thu, 5 Jun 2003 08:09:02 -0500 Subject: Naive question on lists of duplicates Message-ID: <1B097B7096652942BBF2F1ED436CC4E202CE54B8@MSPMAILV2.retek.int> SGksIGFsbC4NCiANCkkgaGF2ZSBhbiBleGNlZWRpbmdseSBzaW1wbGUgcHJvYmxlbSB0byBhZGRy ZXNzLCBhbmQgYW0gd29uZGVyaW5nIGlmIHRoZXJlIGFyZSByZWxhdGl2ZWx5IHN0cmFpZ2h0Zm9y d2FyZCB3YXlzIHRvIGltcHJvdmUgdGhlIGVmZmljaWVuY3kgb2YgbXkgc29sdXRpb24uDQogDQpU aGUgdGFzayBpcyBzaW1wbHkgdG8gbG9vayBhdCBhIGxlbmd0aHkgbGlzdCBvZiBzdG9jayBrZWVw aW5nIHVuaXRzIChTS1VzIC0tIHdoYXQgcmV0YWlsZXJzIGNhbGwgaW5kaXZpZHVhbCBpdGVtcyks IHN0b3JlcywgZGF0ZXMgdGhhdCBhIHByb21vdGlvbiBzdGFydGVkLCBkYXRlcyB0aGUgcHJvbW90 aW9uIGVuZGVkLCBhbmQgc29tZXRoaW5nIGxpa2Ugc2FsZXMgYW1vdW50OyB3ZSB3YW50IHRvIHB1 bGwgb3V0IHRoZSByZWNvcmRzIHdoZXJlIHByb21vdGlvbnMgb3ZlcmxhcC4gIEkgd2lsbCBoYXZl IGRhdGVzIGluIHl5eXltbWRkIGZvcm1hdCwgc28gdGhlcmUncyBwcm9iYWJseSBubyBoYXJtIGlu IHRyZWF0aW5nIHRoZW0gYXMgSW50cy4NCiANCk15IHN1Z2dlc3Rpb24gd2VudCBzb21ldGhpbmcg bGlrZSB0aGlzIChJJ20gbm90IGF0IG15IGRlc2sgc28gSSBkb24ndCBoYXZlIGV4YWN0bHkgd2hh dCBJIHR5cGVkKToNCiANCj4gZGF0YSBQcm9tb3Rpb25SZWMgID0gUFIge3NrdSA6OiBTdHJpbmcs IHN0b3JlIDo6IFN0cmluZywgc3RhcnREYXRlIDo6IEludCwgZW5kRGF0ZSA6OiBJbnQsIGFtb3Vu dDo6RmxvYXR9DQo+DQo+IG1hdGNoICAgICAgICAgICAgICAgICAgICAgIDo6ICBQcm9tb3Rpb25S ZWMgLT4gW1Byb21vdGlvblJlY10gLT4gW1Byb21vdGlvblJlY10NCj4gbWF0Y2ggXyBbXSAgICAg ICAgICAgICAgID0gW10NCj4gbWF0Y2ggeCAoeDp4cykgICAgICAgICA9ICBmaWx0ZXIgKG1lZXQg eCkgeHMNCj4NCj4gbm9tYXRjaCAgICAgICAgICAgICAgICAgOjogIFByb21vUmVjIC0+IFtQcm9t b3Rpb25SZWNdIC0+IFtQcm9tb3Rpb25SZWNdDQo+IG5vbWF0Y2ggXyBbXSAgICAgICAgICA9IFtd DQo+IG5vbWF0Y2ggeCAoeDp4cykgICAgPSAgZmlsdGVyIChub21lZXQgeCkgeHMNCj4NCj4gbWVl dCAgICAgICAgICAgICAgICAgICAgICA6OiBQcm9tb1JlYyAtPiBQcm9tb1JlYyAtPiBCb29sDQo+ IG1lZXQgeCB5ICAgICAgICAgICAgICAgID0gYW5kIFtzdGFydERhdGUgeCA8PSBlbmREYXRlIHks IHN0YXJ0RGF0ZSB5ICA8PSBzdGFydERhdGUgeF0NCj4NCj4gbm9tZWV0ICAgICAgICAgICAgICAg ICAgOjogUHJvbW9SZWMgLT4gUHJvbW9SZWMgLT4gQm9vbA0KPiBub21lZXQgeCB5ICAgICAgICAg ICAgPSBub3QgKG1lZXQgeCB5KQ0KPg0KPiBvdmVybGFwcyAgICAgICAgICAgICAgICA6OiBbUHJv bW9SZWNdIC0+IFtbUHJvbW9SZWNdXQ0KPiBvdmVybGFwcyBbXSAgICAgICAgICAgID0gW10NCj4g b3ZlcmxhcHMgKHg6eHMpICAgICAgPSAgKHggOiBtYXRjaCB4IHhzKSA6IChvdmVybGFwcyAobm9t YXRjaCB4IHhzKSkNCj4NCj4gb3ZlcmxhcCAgICAgICAgICAgICAgICAgOjogW1Byb21vUmVjXSAt PiBbW1Byb21vUmVjXV0NCj4gb3ZlcmxhcCBbXSAgICAgICAgICAgICA9IFtdDQo+IG92ZXJsYXAg KHg6eHMpICAgICAgID0gZmlsdGVyIGcxIChvdmVybGFwcyAoeDp4cykpIHdoZXJlDQo+ICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZzEgeXMgPSAobGVuZ3RoIHlzKSA+IDENCiAN CldoYXQgSSBzZW50IG1pZ2h0IGhhdmUgYmVlbiBzbGlnaHRseSBkaWZmZXJlbnQsIGFuZCBJIG1p Z2h0IGhhdmUgc29tZSB0eXBvcyBpbiB0aGUgYWJvdmUgKGFzIEknbSBjb21wb3NpbmcgZnJvbSBt ZW1vcnkgYXQgdGhlIGtleWJvYXJkKSwgYnV0IHRoYXQncyB0aGUgcm91Z2ggaWRlYTogIHRyZWF0 IHRoaXMgbGlrZSBhIHF1aWNrc29ydCwgcHVsbGluZyBvdXQgdGhlIHJlY29yZHMgdGhhdCBvdmVy bGFwIHRoZSBmaXJzdCByZWNvcmQsIGNvbnNpbmcgdGhlIGZpcnN0IHJlY29yZCBvbnRvIHRoZSBs aXN0LCBhbmQgdGhlbiBjb25zaW5nIHRoZSByZXN1bHRpbmcgbGlzdCBvbnRvIHRoZSBzYW1lIGZ1 bmN0aW9uIGFwcGxpZWQgdG8gdGhlIHJlY29yZHMgdGhhdCBkaWRuJ3Qgb3ZlcmxhcC4gIEFzIGEg bGFzdCBzdGVwLCBkZWxldGUgdGhlIHJlY29yZHMgdGhhdCB3ZXJlIG5vdCBvbiBwcm9tb3Rpb24g d2hpbGUgYW55dGhpbmcgZWxzZSB3YXMgb24gcHJvbW90aW9uLg0KIA0KSSdtIHByZXR0eSBjb25m aWRlbnQgdGhhdCB0aGlzIHdpbGwgYmUgbW9yZSBlZmZpY2llbnQgdGhhbiBteSBjb2xsZWFndWUn cyBTQVMgY29kZSwgYXMgaGUgd2FzIGNvbXBhcmluZyBlYWNoIHJlY29yZCB0byBldmVyeSBvdGhl ciByZWNvcmQgKGdpdmluZyBuIChuLTEpIGNvbXBhcmlzb25zKS4gIEl0IHNlZW1zIGxpa2UgdGhp cywgaW4gdGhlIHdvcnN0IGNhc2Ugd2hlcmUgZXZlcnl0aGluZyBpcyBvbiBwcm9tb3Rpb24gYXQg ZGlzdGluY3QgdGltZXMsIHdpbGwgY29tcGFyZSB0aGUgZmlyc3QgcmVjb3JkIHRvIChuLTEpIHJl Y29yZHMsIHRoZSBzZWNvbmQgdG8gKG4tMikgcmVjb3JkcywgZXRjLiwgZ2l2aW5nIG4gKG4tMSkv MiBjb21wYXJpc29ucy4gIFRodXMsIHdoaWxlIHRoaXMgaXMgd29yc3QtY2FzZSBPKG5eMiksIGl0 IHNlZW1zIGxpa2UgaXQgc2hvdWxkIGhhdmUgYXQgbW9zdCBoYWxmIGFzIG11Y2ggd29yayB0byBk byBhcyB0aGUgZWFybGllciBhcHByb2FjaCBpbiBTQVMuICBPbiB0aGUgb3RoZXIgaGFuZCwgaW4g dGhlIGJlc3QgY2FzZSwgd2hlbiBldmVyeXRoaW5nIGlzIG9uIHByb21vdGlvbiBhdCB0aGUgc2Ft ZSB0aW1lLCB0aGVyZSBzaG91bGQgYmUgc29tZXRoaW5nIGxpa2Ugbi0xIGNvbXBhcmlzb25zIG1h ZGUgYW5kIHRoZW4gdGhhdCBzaG91bGQgYmUgaXQuICBTbyBpdCBzZWVtcyBsaWtlLCBkZXBlbmRp bmcgb24gaG93IGZyZXF1ZW50bHkgcHJvbW90aW9ucyBjby1vY2N1ciBmb3IgdGhpcyByZXRhaWxl ciwgdGhlIGFib3ZlIHNob3VsZCBiZSBzb21ld2hlcmUgYmV0d2VlbiBPKG4pIGFuZCBPKG5eMikg dGltZSBjb21wbGV4aXR5LiAgU2luY2UgdGhlc2UgcGVvcGxlIGFyZSBhbHdheXMgaGF2aW5nIHNv bWUgc2FsZSBvciBvdGhlciwgSSBzdXNwZWN0IHRoaXMgd29uJ3QgYmUgbXVjaCB3b3JzZSB0aGFu IE8obiBsb2cgbikuDQogDQpJcyB0aGVyZSBhbnl0aGluZyB0aGF0IGlzIGFuIG9idmlvdXMgaW1w cm92ZW1lbnQgaW4gZWZmaWNpZW5jeSAtLSBzb21lIGNsZXZlciB0cmlja3Mgd2l0aCB0aGUgZm9s ZCBmdW5jdGlvbnMsIHNvbWUgd2F5IG9mIGxvYWRpbmcgdGhlIGRhdGEgaW50byBzb21lIHNvcnQg b2YgY29udmVuaWVudCBzdHJ1Y3R1cmUgZmlyc3QsIGV0YyAtLSB0aGF0IEkgY291bGQgZWFzaWx5 IGltcGxlbWVudD8NCiANClBsZWFzZSBzaGFyZSB5b3VyIHRob3VnaHRzLg0KIA0KTWFueSB0aGFu a3MsDQpKYWNrIFN0ZWNoZXINCmphY2suc3RlY2hlckByZXRlay5jb20NCg== From sarah@telergy.com Thu Jun 5 14:29:39 2003 From: sarah@telergy.com (Sarah Thompson) Date: Thu, 05 Jun 2003 14:29:39 +0100 Subject: Naive question on lists of duplicates In-Reply-To: <1B097B7096652942BBF2F1ED436CC4E202CE54B8@MSPMAILV2.retek.int> References: <1B097B7096652942BBF2F1ED436CC4E202CE54B8@MSPMAILV2.retek.int> Message-ID: <3EDF45C3.2010605@telergy.com> >I'm pretty confident that this will be more efficient than my colleague'= s SAS code, as he was comparing each record to every other record (giving= n (n-1) comparisons). It seems like this, in the worst case where every= thing is on promotion at distinct times, will compare the first record to= (n-1) records, the second to (n-2) records, etc., giving n (n-1)/2 compa= risons. Thus, while this is worst-case O(n^2), it seems like it should h= ave at most half as much work to do as the earlier approach in SAS. On t= he other hand, in the best case, when everything is on promotion at the s= ame time, there should be something like n-1 comparisons made and then th= at should be it. So it seems like, depending on how frequently promotion= s co-occur for this retailer, the above should be somewhere between O(n) = and O(n^2) time complexity. Since these people are always having some sa= le or other, I suspect this won't be much worse than O(n log n). >=20 >Is there anything that is an obvious improvement in efficiency -- some c= lever tricks with the fold functions, some way of loading the data into s= ome sort of convenient structure first, etc -- that I could easily implem= ent? > =20 > Firstly I'm assuming that you are working with a granularity of days, and= that each promotion will always have a relatively small maximum number o= f days. If so, how about something like the following: 1: Filter the existing data structure, resulting in a lazy list of tuples= (a, b) where a is a day number and b is an identifier for the promotion.= Where a promotion spans n days, the list will contain n entries, one for= each day of the promotion. Complexity is O(M x N), where M is the (small= ) maximum number of days. If this is fixed *and* small, we can discard th= is any regard the complexity as just O(N). 2: Sort the list with a as the primary key and b as the secondary key. Co= mplexity should be near enough O(N log N) 3: Traverse the results of the sort, outputting a lazy list of lists such= that the elements of each sub-list are references to the promotions that= overlap for one specific day number. Where no overlap is detected for on= e specific day, that day can simply be ignored. Complexity should be line= ar. 4: Sort this list, and discard duplicates. Complexity should be O(N log N= ) for the sort and O(N) for the 'uniq'. 5: You are now left with a list which describes all overlapping promotion= s. Total complexity should effectively be O(N + N log N + N + N log N + N) w= hich of course just collapses to O(N log N). --=20 ---------------------------------------------- / __ + / Sarah Thompson **** / / (_ _ _ _ |_ / * / / __)(_|| (_|| ) / sarah@telergy.com * / / + / http://findatlantis.com/ / ---------------------------------------------- From gk@ninebynine.org Thu Jun 5 10:03:55 2003 From: gk@ninebynine.org (Graham Klyne) Date: Thu, 05 Jun 2003 10:03:55 +0100 Subject: powerset In-Reply-To: <20030604195001.00007769.ddarius@hotpop.com> References: <20030604140844.GB11206@boris.qub.ac.uk> <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <20030604140844.GB11206@boris.qub.ac.uk> Message-ID: <5.1.0.14.2.20030605094718.03427ed0@127.0.0.1> At 19:50 04/06/03 -0400, Derek Elkins wrote: > > > foldl (++) [] [ combinations n as | n <- intRange 1 (length as) > > > ] > >*cries out in pain and horror* fold_l_ (++) over combinatorially large >lists! (++) has gotten a reputation for being slow. >(++) isn't slow in and of itself, even using it a lot isn't slow, what >-is- slow is using it left associatively. What happens then is that >(a++b)++c builds a copy of a then tacks on b, then it builds a copy of >a++b and tacks on c. In this case we've copied a twice when we should >have only copied it once. Obviously for ((a++b)++c)++d it'll be copied >three times and b twice and so forth. To add insult to injury, there is >already a standard function that does what you want, concat, which is >defined as foldr (++) [] in the report. In fact, you could rewrite the >whole thing as concatMap (flip combinations as) [1..length as]. A list >comprehension with only one source and no filters is the same as a map. Thank you. I stand duly instructed... this commentary was the kind of feedback I was hoping to draw, though I did not mean to cause so much anguish :-) > > You can also write > > [1..length as] rather than use the intRange function, which looks > > prettier. :-) I agree with Liyang that [1.. ] is much prettier. That's one idiom I've yet to absorb. (I came to functional programming thinking that it was fundamentally simpler than conventional languages -- none of those complicated control structures to worry about, just expressions -- but the syntactic richness of Haskell seems to be quite beyond the conventional languages that I have used.) >Indeed, I think I've used length all of 3 times. This is an interesting comment. I've found myself using length quite often, even when it feels not-quite-right to me. Maybe it's that I'm not yet used to designing algorithms functional-style, or alternative idioms that I'm overlooking. I'm not sure what I'm missing here, so this is a vague probe for further insight. > You (Graham) also have >some parentheses issues; e.g. in foo ++ (combinations 5 l) the >parentheses are superfluous. I'm tempted to argue that being superfluous doesn't mean they shouldn't be there. This isn't just a functional programming issue... I find that when there are many levels of operator precedence it's easier to be explicit than to try and remember what they all are -- as much for reading the code as writing it in the first place. But maybe I'm still reading functional code in the wrong way? (I still scratch my head over some of the prelude/library functions, though it's getting easier.) >(++) is slow though in that seemingly innocent uses can become n^2. A >simple example is displaying a binary tree. A tree like > /\ >/\ >will cause left associative uses of (++). Hence the prelude type ShowS >= String -> String and shows :: Show a => a -> ShowS. The problem is we >don't want left associativity, so what we do is make a context that >says do everything else to the right, then this, e.g. >"Foo"++everythingelse. This is simple enough to do with ("Foo"++). (As >a side note, using the Writer/Output monad with the list/string monoid >is probably not the best of ideas, instead you can use the function >monoid and tell ("foo"++).) You can see that this technique is more or >less just adding an accumulating parameter as you'll have to provide the >'initial' value. I'd just about figured the ShowS idea, but I've yet to get a handle on this idea of [a] 'monoid'. #g ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From Keith.Wansbrough@cl.cam.ac.uk Thu Jun 5 16:20:36 2003 From: Keith.Wansbrough@cl.cam.ac.uk (Keith Wansbrough) Date: Thu, 05 Jun 2003 16:20:36 +0100 Subject: powerset In-Reply-To: Your message of "Thu, 05 Jun 2003 10:03:55 BST." <5.1.0.14.2.20030605094718.03427ed0@127.0.0.1> Message-ID: > > You (Graham) also have > >some parentheses issues; e.g. in foo ++ (combinations 5 l) the > >parentheses are superfluous. > > I'm tempted to argue that being superfluous doesn't mean they shouldn't be > there. This isn't just a functional programming issue... I find that when > there are many levels of operator precedence it's easier to be explicit > than to try and remember what they all are -- as much for reading the code > as writing it in the first place. But maybe I'm still reading functional > code in the wrong way? (I still scratch my head over some of the > prelude/library functions, though it's getting easier.) This is a particular instance where you never need the parentheses... since it's a _functional_ language, _function application_ (the invisible symbol between combinations and 5, and between combinations 5 and l) binds tighter than anything else. The only time you need parentheses around a function application are when it is to protect it from a competing function application, such as when you are passing it as an argument to a function: map (map f) xss rather than map map f xss HTH. --KW 8-) From GK@ninebynine.org Thu Jun 5 17:41:45 2003 From: GK@ninebynine.org (Graham Klyne) Date: Thu, 05 Jun 2003 17:41:45 +0100 Subject: powerset In-Reply-To: <3EDF0810.1040701@info.unicaen.fr> References: <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604214132.033fc090@127.0.0.1> Message-ID: <5.1.0.14.2.20030605173720.032b5db8@127.0.0.1> At 11:06 05/06/03 +0200, Jerzy Karczmarczuk wrote: >I permit myself to observe that your powerset problem (and the restricted >length problem, i.e. the combinations) is usually solved in Prolog, through >backtracking, using reasoning/style which adopts this "individualistic" >philosophy. > >powerset(,) --- is the pattern. And the >solution is > >powerset([],[]). Since nothing else can be done. Otherwise you pick the item > or not. > >powerset([X|Rest],L) :- powerset(Rest,L). >powerset([X|Rest],[X|L) :- powerset(Rest,L). If my (rusty) Prolog serves, this will still fail to generate the shorter sequences before the longer ones, as I think that all powerset members not containing X must be generated before any that do contain X. (Or is that a different thread of discussion I'm introducing here?) >The xxx ++ map (x :) xxx solution in Haskell is a particular formulation >(and optimization) of the straightforward transformation from a version >using the non-deterministic Monad. This one is really almost a carbon copy >of the Prolog solution, with appropriate "lifting" of operations from >individuals to lazy lists. It is the case that I'm finding it very easy to code solutions that work very much like Prolog backtracking using what I think is a form of "non-deterministic Monad" (e.g. a list, lazily evaluated, used to return the set of all results?) #g ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From liyang@nerv.cx Thu Jun 5 18:44:41 2003 From: liyang@nerv.cx (Liyang HU) Date: Thu, 5 Jun 2003 18:44:41 +0100 Subject: powerset In-Reply-To: <5.1.0.14.2.20030605094718.03427ed0@127.0.0.1> References: <20030604140844.GB11206@boris.qub.ac.uk> <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <20030604140844.GB11206@boris.qub.ac.uk> <5.1.0.14.2.20030605094718.03427ed0@127.0.0.1> Message-ID: <20030605174441.GE11206@boris.qub.ac.uk> On Thu, Jun 05, 2003 at 10:03:55AM +0100, Graham Klyne wrote: > At 19:50 04/06/03 -0400, Derek Elkins wrote: > > You (Graham) also have some parentheses issues; e.g. in foo ++ > > (combinations 5 l) the parentheses are superfluous. > I'm tempted to argue that being superfluous doesn't mean they > shouldn't be there. Keith already made one argument for less parentheses, here's my take on the subject: Given that: (++) :: [a] -> [a] -> [a] -- contatenates lists foo, l :: [a] -- are lists bar :: Int -> [a] -> [a] -- produces a list Which of the following make sense? > (foo ++) bar 5 l -- No, because bar isn't a list, > (foo ++ bar) 5 l -- and 5 and l would be applied to a list, > (foo ++ bar 5) l -- (as opposed to a function,) which make no sense > foo (++ bar 5 l) -- Can't apply a function to a value, > -- though (++ bar 5 l) foo has the same effect as what we intended > foo ++ (bar 5 l) -- which is just foo ++ bar 5 l Because of the static type checking that takes place, you can't easily (not unless you were _trying_ ;) produce an ambiguous expression such that the removal of brackets keeps it well-typed, yet is not equivalent to the original. So as opposed to the C code where you (and I) would put in extra brackets `just to be sure', I wouldn't bother with them unless I know the expression's going to be ambiguous. (or if the compiler tells me so. ;-) (I suppose you could argue it's not necessarily obvious that foo is a list and bar is a 2-ary function of an Int and a list. My response would be to rename foo and bar so that this is the case. ;-) > I'd just about figured the ShowS idea, but I've yet to get a handle on this > idea of [a] 'monoid'. Might http://www.engr.mun.ca/~theo/Misc/haskell_and_monads.htm be of any help? later, /Liyang -- who managed to sneak into Category Theory lectures, but still has no idea what a monad is. ^_^; -- .--| Liyang HU |--| http://nerv.cx/ |--| Caius@Cam |--| ICQ: 39391385 |--. | :::::::::::::::::::::: This is not a signature. :::::::::::::::::::::: | From liyang@nerv.cx Thu Jun 5 19:33:45 2003 From: liyang@nerv.cx (Liyang HU) Date: Thu, 5 Jun 2003 19:33:45 +0100 Subject: Naive question on lists of duplicates In-Reply-To: <1B097B7096652942BBF2F1ED436CC4E202CE54B8@MSPMAILV2.retek.int> References: <1B097B7096652942BBF2F1ED436CC4E202CE54B8@MSPMAILV2.retek.int> Message-ID: <20030605183345.GF11206@boris.qub.ac.uk> On Thu, Jun 05, 2003 at 08:09:02AM -0500, Stecher, Jack wrote: > The task is simply to look at a lengthy list of stock keeping units (SKUs > -- what retailers call individual items), stores, dates that a promotion > started, dates the promotion ended, and something like sales amount; we > want to pull out the records where promotions overlap. I will have dates > in yyyymmdd format, so there's probably no harm in treating them as Ints. (Disclaimer: provided I've understood your problem correctly...) For `heap' below, read `Data.FiniteMap'. Create an empty heap. For each record, For each day the promotion runs, Insert the record[1] into the heap with the date as the key. If it clashes with an existing element, then we've an overlap, Store both records in another heap keyed on the SKU. We can ignore clashes. Don't forget to insert the rest of the dates. (I'm sure there's plenty of optimisations that can be done here...) [1] Or at least the SKU, or anything that can uniquely identify the promotion. As Sarah said, _provided_ there's a small bound on the number of days that a promotion can run for, then we can assume it to be a constant, resulting in an O(n log n) algorithm. Your dates are already Ord'ered, so that's good. The only niggle I see is that you're going to have to figure out some way of generating all the dates for which a promotion runs, which is going to be messy. Thankfully (I think) the System.Time module should take care of this for you, if you can massage your existing dates into some workable form... /Liyang [0] or some other suitable data structure. I like heaps because you can avoid costly O(n^2) duplicate checking by paying a price of O(log n) for each insertion. :) -- .--| Liyang HU |--| http://nerv.cx/ |--| Caius@Cam |--| ICQ: 39391385 |--. | :::::::::::::::::::::: This is not a signature. :::::::::::::::::::::: | From mpj@cse.ogi.edu Fri Jun 6 04:25:54 2003 From: mpj@cse.ogi.edu (Mark P Jones) Date: Thu, 5 Jun 2003 20:25:54 -0700 Subject: powerset In-Reply-To: Message-ID: <000101c32bdb$6043e3c0$09315f81@blue> | powerset :: [a] -> [[a]] | powerset [] = [[]] | powerset (x:xs) = xss ++ map (x:) xss | where xss = powerset xs Elegant as it is, this program causes a serious space leak. (In fact, it is often cited as an example of why functional programming language implementations might choose not to use common subexpression elimination.) Why? Because it holds on to the whole of xss until the first half of the resulting list has been generated. And xss gets big, fast. In Hugs, try: :set +g length (powerset [1..32]) and watch as your free heap disappears ... One way to fix this is to rewrite the second line in the definition of powerset as: powerset (x:xs) = powerset xs ++ map (x:) (powerset xs) Or, if duplicated computation offends you, replace (++) in the original version of powerset with an interleave operator: powerset :: [a] -> [[a]] powerset [] = [[]] powerset (x:xs) = xss /\/ map (x:) xss where xss = powerset xs (/\/) :: [a] -> [a] -> [a] [] /\/ ys = ys (x:xs) /\/ ys = x : (ys /\/ xs) These two variants both run in constant space (assuming that your compiler isn't "smart" enough to do common subexpr elimination :-) All the best, Mark From IMCEAEX-_O=MICROSOFT_OU=NORTHAMERICA_CN=RECIPIENTS_CN=428592@microsoft.com Fri Jun 6 08:15:14 2003 From: IMCEAEX-_O=MICROSOFT_OU=NORTHAMERICA_CN=RECIPIENTS_CN=428592@microsoft.com (Simon Peyton-Jones) Date: Fri, 6 Jun 2003 08:15:14 +0100 Subject: Network.CGI Message-ID: If anyone cares to write some (Haddockised), we'd be happy to paste it into the source code. Simon | -----Original Message----- | From: haskell-cafe-admin@haskell.org [mailto:haskell-cafe-admin@haskell.org] On | Behalf Of Thomas L. Bevan | Sent: 04 June 2003 08:29 | To: haskell-cafe@haskell.org | Subject: Network.CGI |=20 | Can anyone point me to some documentation on the Network.CGI package? |=20 | The wrapper fn is clear enough but I'm not sure what | pwrapper is for or the nature of the contract in connectToCGIScript |=20 | Tom |=20 | _______________________________________________ | Haskell-Cafe mailing list | Haskell-Cafe@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-cafe From GK@ninebynine.org Thu Jun 5 19:29:19 2003 From: GK@ninebynine.org (Graham Klyne) Date: Thu, 05 Jun 2003 19:29:19 +0100 Subject: powerset In-Reply-To: References: Message-ID: <5.1.0.14.2.20030605192621.00bb1978@127.0.0.1> At 16:20 05/06/03 +0100, Keith Wansbrough wrote: >This is a particular instance where you never need the >parentheses... since it's a _functional_ language, _function >application_ ... binds tighter than anything else. Ah, fair point. I hadn't fully internalized that function application binds tighter than any (explicit) infix operator. (Reading it is one thing...) #g ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From GK@ninebynine.org Fri Jun 6 12:47:41 2003 From: GK@ninebynine.org (Graham Klyne) Date: Fri, 06 Jun 2003 12:47:41 +0100 Subject: powerset In-Reply-To: <000101c32bdb$6043e3c0$09315f81@blue> References: Message-ID: <5.1.0.14.2.20030606121615.02dd1470@127.0.0.1> At 20:25 05/06/03 -0700, Mark P Jones wrote: >Or, if duplicated computation offends you, replace (++) in the >original version of powerset with an interleave operator: > > powerset :: [a] -> [[a]] > powerset [] = [[]] > powerset (x:xs) = xss /\/ map (x:) xss > where xss = powerset xs > > (/\/) :: [a] -> [a] -> [a] > [] /\/ ys = ys > (x:xs) /\/ ys = x : (ys /\/ xs) > >These two variants both run in constant space (assuming that >your compiler isn't "smart" enough to do common subexpr >elimination :-) Interesting... Picking up my theme or generating the powersets in increasing order of length, I tried a variation on that: [[ powerset3 :: [a] -> [[a]] powerset3 [] = [[]] powerset3 (x:xs) = xss <<< map (x:) xss where xss = powerset3 xs (<<<) :: [[a]] -> [[a]] -> [[a]] [] <<< ys = ys xs <<< [] = xs (x:xs) <<< (y:ys) = if length x < length y then x:(xs <<< (y:ys)) else y:((x:xs) <<< ys) testJ1 = powerset3 [1,2,3,4] testJ2 = powerset3 "abcdefgh" ]] (The length-ordered interleave is a bit clumsy -- I think that could be improved by saving the length with each powerset as it's generated, or by other means.) Empirically, I notice that this still seems to leak *some* space compared with your version, but not nearly as much as the simple version. I also notice, empirically, that these interleaving versions invoke garbage collection much more frequently than the naive version. #g ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From maeder@tzi.de Fri Jun 6 16:38:50 2003 From: maeder@tzi.de (Christian Maeder) Date: Fri, 06 Jun 2003 17:38:50 +0200 Subject: powerset In-Reply-To: <5.1.0.14.2.20030606121615.02dd1470@127.0.0.1> References: <5.1.0.14.2.20030606121615.02dd1470@127.0.0.1> Message-ID: <3EE0B58A.3010705@tzi.de> powerset :: [a] -> [[a]] powerset [] = [[]] powerset (x:xs) = concatMap ( \ s -> s:[x:s]) (powerset xs) this variant behaves as well, doesn't it? >> powerset :: [a] -> [[a]] >> powerset [] = [[]] >> powerset (x:xs) = xss /\/ map (x:) xss >> where xss = powerset xs >> >> (/\/) :: [a] -> [a] -> [a] >> [] /\/ ys = ys >> (x:xs) /\/ ys = x : (ys /\/ xs) >> >> These two variants both run in constant space (assuming that >> your compiler isn't "smart" enough to do common subexpr >> elimination :-) > Picking up my theme or generating the powersets in increasing order of > length, I tried a variation on that: powerset :: [a] -> [(Int, [a])] powerset [] = [(0, [])] powerset (x:xs) = myconcat $ map ( \ s -> (s, (fst s + 1, x: snd s))) $ powerset xs myconcat :: [((Int, [a]), (Int, [a]))] -> [(Int, [a])] myconcat [(a,b)] = [a, b] myconcat (x:r) = insert x $ myconcat r insert :: ((Int, [a]), (Int, [a])) -> [(Int, [a])] -> [(Int, [a])] insert (a@(i,_), b) l@(c@(j, _) : r) = if i < j then a : b : l else c : insert (a, b) r However, length (powerset [1..32]) in Hugs ends in an: ERROR - Control stack overflow Cheers Christian > > [[ > powerset3 :: [a] -> [[a]] > powerset3 [] = [[]] > powerset3 (x:xs) = xss <<< map (x:) xss > where xss = powerset3 xs > > (<<<) :: [[a]] -> [[a]] -> [[a]] > [] <<< ys = ys > xs <<< [] = xs > (x:xs) <<< (y:ys) = if length x < length y > then x:(xs <<< (y:ys)) > else y:((x:xs) <<< ys) > > testJ1 = powerset3 [1,2,3,4] > testJ2 = powerset3 "abcdefgh" > ]] > > (The length-ordered interleave is a bit clumsy -- I think that could be > improved by saving the length with each powerset as it's generated, or > by other means.) > > Empirically, I notice that this still seems to leak *some* space > compared with your version, but not nearly as much as the simple > version. I also notice, empirically, that these interleaving versions > invoke garbage collection much more frequently than the naive version. From GK@ninebynine.org Fri Jun 6 18:46:59 2003 From: GK@ninebynine.org (Graham Klyne) Date: Fri, 06 Jun 2003 18:46:59 +0100 Subject: Collecting values from Functors? In-Reply-To: <20030604184057.GB26522@students.mimuw.edu.pl> References: <20030604183828.GA26522@students.mimuw.edu.pl> <5.1.0.14.2.20030604190437.030c99f0@127.0.0.1> <20030604183828.GA26522@students.mimuw.edu.pl> Message-ID: <5.1.0.14.2.20030606183034.02db7008@127.0.0.1> [Moved to haskell-cafe] At 20:40 04/06/03 +0200, Tomasz Zielonka wrote: > > > > I'm trying to figure if there's any way I can use (say) monads to > collect > > > > values from a Functor. > > > > > > > > For example, suppose I have a tree of some values that supports > fmap, is > > > > there any way I can use the fmap function to collect a list of all > the node > > > > values? > > > > > > No, you need a fold to do that. > > > Or a variant of Functor constructor class that I have proposed some time > > ago on comp.lang.functional: > > > > class FunctorM t where > > fmapM :: Monad m => (a -> m b) -> (t a -> m (t b)) > > fmapM_ :: Monad m => (a -> m b) -> (t a -> m ()) > > fmapM_ f t = fmapM f t >> return () > > > > instance FunctorM [] where > > fmapM = mapM > > fmapM_ = mapM_ I've done a little playing with this, which seems to work on a small scale, and am just wanting to check if I am properly understanding your idea... 'Arc' is a small part of a data structure I am playing with, which is currently a Functor. I've made this an instance of FunctorM, defining fmapM which has some recognizable similarity with fmap. Finally, there's a monad type CollectNodes using Control.Monad.State and constructor function mungeNode to actually apply the transformation and collect results. It seems to work -- is this roughly what you envisaged? [[ -- spike-FunctorM.hs import Control.Monad.State class FunctorM t where fmapM :: Monad m => (a -> m b) -> (t a -> m (t b)) fmapM_ :: Monad m => (a -> m b) -> (t a -> m ()) fmapM_ f t = fmapM f t >> return () data Arc lb = Arc { asubj, apred, aobj :: lb } deriving (Eq, Show) instance Functor Arc where fmap f (Arc s p o) = Arc (f s) (f p) (f o) instance FunctorM Arc where -- fmapM :: (lb -> m l2) -> Arc lb -> m (Arc l2) fmapM f (Arc s p o) = do { s' <- f s ; p' <- f p ; o' <- f o ; return $ Arc s' p' o' } -- CollectNodes a b is a state transformer on a state of -- type '[a]', which additionally returns a value of type 'b'. type CollectNodes a b = State [a] b -- constructor State { runState :: (s -> (a, s)) } -- runState :: State s a -> s -> (a, s) -- evalState :: State s a -> s -> a -- execState :: State s a -> s -> s -- mapState :: ((a, s) -> (b, s)) -> State s a -> State s b -- withState :: (s -> s) -> State s a -> State s a -- instance MonadState s (State s) -- get :: m s -- (CollectNodes a b) [a] -- put :: s -> m () -- modify :: (MonadState s m) => (s -> s) -> m () -- gets :: (MonadState s m) => (s -> a) -> m a mungeNode :: lb -> CollectNodes lb (Maybe lb) mungeNode lab = do { modify (lab:) -- accumulate labels ; return (Just lab) -- return modified label } a1 = Arc "s1" "p1" "o1" r1 = runState ( fmapM mungeNode a1 ) [] ]] I think, but haven't worked out the details, that one could define fmap in terms of fmapM. (I read somewhere about an identity Monad, but can't recall the reference -- I think that might do it.) I'm also harbouring a suspiscion that this FunctorM framework might be subsumed by gmap and friends, but I'll leave that for another day. #g ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From ralf@informatik.uni-bonn.de Fri Jun 6 19:52:57 2003 From: ralf@informatik.uni-bonn.de (Ralf Hinze) Date: Fri, 6 Jun 2003 20:52:57 +0200 Subject: Collecting values from Functors? In-Reply-To: <5.1.0.14.2.20030606183034.02db7008@127.0.0.1> References: <20030604183828.GA26522@students.mimuw.edu.pl> <5.1.0.14.2.20030606183034.02db7008@127.0.0.1> Message-ID: <200306062052.57153.ralf@informatik.uni-bonn.de> > class FunctorM t where > fmapM :: Monad m => (a -> m b) -> (t a -> m (t b)) > fmapM_ :: Monad m => (a -> m b) -> (t a -> m ()) > fmapM_ f t = fmapM f t >> return () The `fmapM' function is also known as a monadic map. It can be defined in a generic way for every Haskell data type. It's in the library of Generic Haskell (called mapMl): http://www.cs.uu.nl/research/projects/generic-haskell/ As an aside, gmap and friends won't fit the bill, as they work on types rather than functors. Cheers, Ralf From gk@ninebynine.org Fri Jun 6 21:54:57 2003 From: gk@ninebynine.org (Graham Klyne) Date: Fri, 06 Jun 2003 21:54:57 +0100 Subject: Collecting values from Functors? In-Reply-To: <200306062052.57153.ralf@informatik.uni-bonn.de> References: <5.1.0.14.2.20030606183034.02db7008@127.0.0.1> <20030604183828.GA26522@students.mimuw.edu.pl> <5.1.0.14.2.20030606183034.02db7008@127.0.0.1> Message-ID: <5.1.0.14.2.20030606214938.02e52500@127.0.0.1> At 20:52 06/06/03 +0200, Ralf Hinze wrote: > > class FunctorM t where > > fmapM :: Monad m => (a -> m b) -> (t a -> m (t b)) > > fmapM_ :: Monad m => (a -> m b) -> (t a -> m ()) > > fmapM_ f t = fmapM f t >> return () > >The `fmapM' function is also known as a monadic map. It can be >defined in a generic way for every Haskell data type. It's in >the library of Generic Haskell (called mapMl): > > http://www.cs.uu.nl/research/projects/generic-haskell/ So much to learn! I must try and read it all. One day. A brief chase of that link didn't show up anything that was obviously about monadic maps... do you have any more specific links? >As an aside, gmap and friends won't fit the bill, as they work >on types rather than functors. As it happens, I think what I described was based on the type rather than the Functor (the message subject may have been misleading), because I didn't actually use the existing fmap definition, but defined a new function with certain similarities. #g ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From dpt@math.harvard.edu Sat Jun 7 02:06:29 2003 From: dpt@math.harvard.edu (Dylan Thurston) Date: Sat, 7 Jun 2003 03:06:29 +0200 Subject: Naive question on lists of duplicates In-Reply-To: <1B097B7096652942BBF2F1ED436CC4E202CE54B8@MSPMAILV2.retek.int> References: <1B097B7096652942BBF2F1ED436CC4E202CE54B8@MSPMAILV2.retek.int> Message-ID: <20030607010629.GA32495@lotus.bostoncoop.net> --d6Gm4EdcadzBjdND Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Thu, Jun 05, 2003 at 08:09:02AM -0500, Stecher, Jack wrote: > I have an exceedingly simple problem to address, and am wondering if > there are relatively straightforward ways to improve the efficiency > of my solution. Was there actually a problem with the efficiency of your first code? > The task is simply to look at a lengthy list of stock keeping units > (SKUs -- what retailers call individual items), stores, dates that a > promotion started, dates the promotion ended, and something like > sales amount; we want to pull out the records where promotions > overlap. I will have dates in yyyymmdd format, so there's probably > no harm in treating them as Ints. (Unless this is really a one-shot deal, I suspect using Ints for dates is a bad decision...) > My suggestion went something like this (I'm not at my desk so I > don't have exactly what I typed): I have a different algorithm, which should be nearly optimal, but I find it harder to describe than to show the code (which is untested): > import List(sortBy, insertBy) > > data PromotionRec =3D PR {sku :: String, store :: String, startDate :: I= nt, endDate :: Int, amount::Float} > > compareStart, compareEnd :: PromotionRec -> PromotionRec -> Ordering > compareStart x y =3D compare (startDate x) (startDate y) > compareEnd x y =3D compare (endDate x) (endDate y) > overlap :: [PromoRec] -> [[PromoRec]] > overlap l =3D filter (lambda l. length l > 1)=20 > (overlap' [] (sortBy compareStart l)) > > overlap' _ [] =3D [] > overlap' active (x:xs) =3D > let {active' =3D dropWhile (lambda y. endDate y < startDate x) active} = in > (x:active') : overlap' (insertBy compareEnd x active') xs The key is that, by keeping a list of the currently active promotions in order sorted by the ending date, we only need to discared an initial portion of the list. You could get a moderately more efficient implementation by keeping the active list as a heap rather than a list. Peace, Dylan --d6Gm4EdcadzBjdND Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQE+4TqVVeybfhaa3tcRAvYYAJ9JwrS6WKViKTB1lOxArpojN3JbvACggTvN aMltiRdkXtFNrSTI8BBpPXc= =mlll -----END PGP SIGNATURE----- --d6Gm4EdcadzBjdND-- From jack.stecher@retek.com Sun Jun 8 02:24:41 2003 From: jack.stecher@retek.com (Stecher, Jack) Date: Sat, 7 Jun 2003 20:24:41 -0500 Subject: Naive question on lists of duplicates Message-ID: <1B097B7096652942BBF2F1ED436CC4E202CE54C0@MSPMAILV2.retek.int> Thanks so much for the reply. On Thu, Jun 06, 2003 at 08:06 PM, Dylan Thurston wrote: > Was there actually a problem with the efficiency of your first code? No -- it was untested, and as I developed more of the code in Haskell, I found that there were slight differences between what I thought we needed to do and what my co-worker had in mind. So, even if my co-worker goes back to writing things in SAS, this has already been helpful for clarifying requirements. In particular, it turns out that he needs to know when promotions overlap for the same SKU, as this is an indication that the data we've received are invalid. I tested the mergeSort to make sure I didn't have any errors, though I used the fairly standard one. It was much faster than a sort in SAS, at least with a PROC SQL, though I ran into size limitations because I had to compile on the Windows side. (We don't have gcc installed on our UNIX side, so ghci will work but ghc won't compile my code.) Since I'm analyzing roughly 600MB of data, I will probably add a step or two in order to chunk the data. In any case, I'm not noticing any obvious inefficiencies, but my Haskell programming is self-taught, and this is my first attempt at solving a real problem at work using Haskell, so I figured I'd get feedback from the list. > (Unless this is really a one-shot deal, I suspect using Ints for dates > is a bad decision...) When I first read this message, I thought, "Well, this really is only a one-shot deal." However, as I thought more about this, I decided that I should write this so that we can use it in case another client comes along with similar data for us to analyze on another project. So I will change this and define a date type, or else I'll read the ghc documentation and learn how to use what's in the time library. > import List(sortBy, insertBy) > > data PromotionRec =3D PR {sku :: String, store :: String, startDate = :: Int, endDate :: Int, amount::Float} As it turns out, the same promotions are always on across all stores. Thus, each SKU/startDate/endDate will seem to have a duplicate promotion. Also, I don't need the amount information, so I wrote the import function so that it would ignore the amount information. One further change: the SKU and store are identified by their number, not their descriptions. The new data type is like this: data PromoRec =3D PR {startDate, endDate, skuID, storeID :: Int} deriving Show though I will likely implement a better show function and will, as noted above, change the dates to a date type. The file is a fixed-width file, so I just do this: loadData :: Handle -> IO [String] loadData handle =3D do s <- hGetContents handle return (lines s) toPromoRecs :: [String] -> [PromoRec] toPromoRecs [] =3D [] toPromoRecs (x:xs) =3D (PR (read (take 8 x)) (read (take 8 (drop 8 x))) (read (take 20 (drop 16 x))) (read (take 20 (drop 36 x)))) : toPromoRecs xs There's probably a much more clever way to do this, but it seems fairly fast. The file allowed 20 spaces for the SKU and store numbers, but they're at most 7 digits long. Again, I'll need to change the first and second reads to some function that converts a string in the form yyyymmdd into a date type (or I'll need to write one). > compareStart, compareEnd :: PromotionRec -> PromotionRec -> Ordering > compareStart x y =3D compare (startDate x) (startDate y) > compareEnd x y =3D compare (endDate x) (endDate y) This is helpful; I'll also need to add a function like this: compareSku :: PromoRec -> PromoRec -> Ordering compareSku x y =3D compare (skuID x) (skuID y) > overlap :: [PromoRec] -> [[PromoRec]] > overlap l =3D filter (lambda l. length l > 1)=20 > (overlap' [] (sortBy compareStart l)) > > overlap' _ [] =3D [] > overlap' active (x:xs) =3D > let {active' =3D dropWhile (lambda y. endDate y < startDate x) = active} in > (x:active') : overlap' (insertBy compareEnd x active') xs Okay; I see what additional modifications I should make. I need to add a step sort by store and delete duplicate stores where the SKU, start date, and end date are the same. But I should be able to get there from here. > The key is that, by keeping a list of the currently active promotions > in order sorted by the ending date, we only need to discared an > initial portion of the list. Good insight. Many thanks. > You could get a moderately more efficient implementation by keeping > the active list as a heap rather than a list. I had thought about that, and took the BinomialHeap.hs file from Okasaki, but I must have a typo somewhere, because I was having typing clashes that I couldn't easily clarify. At least, when I loaded the BinomialHeap.hs into Hugs, it didn't complain, but when I tried to create an empty heap using the heapEmpty function, Hugs screamed at me. I got scared and fled the scene, retreating into the safety of lists. Thanks again, Jack From dpt@math.harvard.edu Sun Jun 8 10:41:22 2003 From: dpt@math.harvard.edu (Dylan Thurston) Date: Sun, 8 Jun 2003 11:41:22 +0200 Subject: Naive question on lists of duplicates In-Reply-To: <1B097B7096652942BBF2F1ED436CC4E202CE54C0@MSPMAILV2.retek.int> References: <1B097B7096652942BBF2F1ED436CC4E202CE54C0@MSPMAILV2.retek.int> Message-ID: <20030608094122.GA12762@lotus.bostoncoop.net> --EeQfGwPcQSOJBaQU Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Sat, Jun 07, 2003 at 08:24:41PM -0500, Stecher, Jack wrote: It sounds like you're on the right track... > > You could get a moderately more efficient implementation by keeping > > the active list as a heap rather than a list. >=20 > I had thought about that, and took the BinomialHeap.hs file from > Okasaki, but I must have a typo somewhere, because I was having typing > clashes that I couldn't easily clarify. At least, when I loaded the > BinomialHeap.hs into Hugs, it didn't complain, but when I tried to > create an empty heap using the heapEmpty function, Hugs screamed at me. > I got scared and fled the scene, retreating into the safety of lists. I don't think you should worry about this now, but the problem was problem that heapEmpty returns something like 'Heap a', for an undetermined type variable 'a'; you may need to specify the type of your empty heap in order for Hugs not to complain. Peace, Dylan --EeQfGwPcQSOJBaQU Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQE+4wTBVeybfhaa3tcRAnR0AJ9Ee/IuDU0B9adpGabJGo8XY4C69QCeN8LL VLUlWI+SzZ5UhwMCTVPNSKI= =UHrf -----END PGP SIGNATURE----- --EeQfGwPcQSOJBaQU-- From GK@ninebynine.org Sun Jun 8 09:06:12 2003 From: GK@ninebynine.org (Graham Klyne) Date: Sun, 08 Jun 2003 09:06:12 +0100 Subject: powerset In-Reply-To: <20030605174441.GE11206@boris.qub.ac.uk> References: <5.1.0.14.2.20030605094718.03427ed0@127.0.0.1> <20030604140844.GB11206@boris.qub.ac.uk> <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <20030604140844.GB11206@boris.qub.ac.uk> <5.1.0.14.2.20030605094718.03427ed0@127.0.0.1> Message-ID: <5.1.0.14.2.20030608090448.02423358@127.0.0.1> At 18:44 05/06/03 +0100, Liyang HU wrote: > > I'd just about figured the ShowS idea, but I've yet to get a handle on > this > > idea of [a] 'monoid'. > >Might http://www.engr.mun.ca/~theo/Misc/haskell_and_monads.htm be of any >help? Ah, thanks. I see: [[ A monoid is an algebraic structure consisting of a set S and an operation * with the following properties ... ]] which is a datum I was missing. (I still don't claim to understand it all, but at least I get a sense of whet the term monoid means.) #g ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From christian@snowblack.de Sun Jun 8 17:22:06 2003 From: christian@snowblack.de (Christian Buschmann) Date: Sun, 08 Jun 2003 18:22:06 +0200 Subject: Fudgets Message-ID: <3EE362AE.9020100@gmx.net> Hi! Is there any easy way to display an IO String with Fudgets? I know how to display a String: import Fudgets main :: IO () main = fudlogue (shellF "Prog" showMe) showMe = ("Hello " `labLeftOfF` displayF) >==< mapF getString >==< (buttonF "ClickMe!") getString :: Click -> String getString Click = "World!" But if I change the getString-function to: getString :: Click -> IO String getString Click = return "World!" --or any other kind of function which returns an IO String I get an error message. Is there any way, without using unsafePerformIO, to display my IO String? thanks Christian Buschmann From hallgren@cse.ogi.edu Sun Jun 8 18:34:18 2003 From: hallgren@cse.ogi.edu (Thomas Hallgren) Date: Sun, 08 Jun 2003 10:34:18 -0700 Subject: Fudgets In-Reply-To: <3EE362AE.9020100@gmx.net> References: <3EE362AE.9020100@gmx.net> Message-ID: <3EE3739A.3060800@cse.ogi.edu> Christian Buschmann wrote: > Hi! > Is there any easy way to display an IO String with Fudgets? The fudget library was designed before Haskell switched to monadic IO, and there is still no support for combining arbitrary monadic IO and fudgets. There are fudgets like stdinF that might be useful, see the section called InOut in the fudget library reference manual. http://www.cs.chalmers.se/Cs/Research/Functional/Fudgets/Manual/current/small.html#InOut -- Thomas H "I think it would be a great idea." (Ghandi's answer when asked what he thought of Western Civilization) From ashley@semantic.org Mon Jun 9 01:57:15 2003 From: ashley@semantic.org (Ashley Yakeley) Date: Sun, 08 Jun 2003 17:57:15 -0700 Subject: Fudgets References: <3EE362AE.9020100@gmx.net> <3EE3739A.3060800@cse.ogi.edu> Message-ID: In article <3EE3739A.3060800@cse.ogi.edu>, Thomas Hallgren wrote: > The fudget library was designed before Haskell switched to monadic IO, > and there is still no support for combining arbitrary monadic IO and > fudgets. Would it be worth rewriting Fudgets to take advantage of such recent advances in Haskell as monadic IO? I must confess I'm not all that familiar with Fudgets, although it certainly looks interesting. For what sort of problems is it currently the best solution? -- Ashley Yakeley, Seattle WA From alistair@abayley.org Mon Jun 9 21:51:00 2003 From: alistair@abayley.org (Alistair Bayley) Date: Mon, 9 Jun 2003 21:51:00 +0100 Subject: Compiling hws with ghc 6 Message-ID: I'm trying to compile the haskell web server (from the haskell-libs project at sf.net) with ghc6 and I'm stuck on the last function in Util.hs: statMaybe filename = do maybe_stat <- tryJust ioErrors (getFileStatus filename) case maybe_stat of Left e -> do errno <- getErrorCode if errno == eNOENT then return Nothing else ioError e Right stat -> return (Just stat) What are the equivalents for getFileStatus and getErrorCode these days? I suppose Foreign.C.Error.getErrno might substitute for getErrorCode, but I'm stumped on getFileStatus. From djsavimbi@phantomemail.com Mon Jun 9 11:55:21 2003 From: djsavimbi@phantomemail.com (David Savimbi) Date: Mon, 9 Jun 2003 11:55:21 +0100 Subject: Please Help! Message-ID: <20030609230354.E075B421EEB@www.haskell.org> From=3A David Jonas Savimbi Johannesburg=2C South Africa Email=3A djsavimbi=40phantomemail=2Ecom June 9th=2C 2003=2E Dear Sir=2C It is my humble pleasure to write you this letter irrespective of the fact that you do not know me=2E However=2C I got your name through your country business directory here in my search for a reliable and trustworthy person that can assist me confidently=2E My name is Mr=2EJohn Jonas Savimbi=2E I am the son of Late Dr=2E Jonas Savimbi from Angola=2E I am 29 years old and I have got two younger sisters of same blood=2E Our mother died almost a year ago=2E We are all fighting for political asylum in South Africa=2E We cannot find a home in Angola anymore because of the war that our late father fought with the government of Angola until he died in that war=2E The government of Angola is now mad at us because our late father also wanted to be president and caused the people to fight the war for him because he was the president of UNITA political movement of Angola=2E So now we are in South Africa and we are suffering too much because we don't have money and the government of South Africa will not give jobs to asylum seekers=2E I am much concerned about my younger sisters who are finding it very difficult to manage in the situation=2E But I know that we should not suffer this way=2E I know that I must not let my younger sisters get into trouble because of money=2E So after consideration I am hereby begging for your assistance to help me to recover the sum of USD $29 Million which is my inheritance from my late mother=2E My late mother had taken this money with her to Spain in a diplomatic metal box marked =28Precious Stones=29=2E Subsequently she lodged the metal box =28As precious Stones=29 with a Securities and Valuables Protection company in Spain=2E I am supposed to be the beneficiary in the event of her death=2E However=2C all effort I made to go Spain to claim was refused by the Spainish embassy=2E And this was while it was still possible for me to travel=2E Now I cannot travel anywhere anymore=2E So in the situation that we are facing now=2C I must find somebody who can go to the Spain on my behalf=2E I understand that I will have to transfer my beneficiary rights unto you=2E I am willing to do so in the hope that you are a God fearing person who will not abandon us after you have the money=2E So from the bottom of my heart I am giving you 20% of the all the money=2E Once we have enough to sustain us sufficiently=2C you may be come our fund manager and invest the rest wisely for us=2E If you will be kind to assist us=2C please inform me urgently=2E Kind regards to you and your family=2E Sincerely=2C David Jonas savimbi From cwitty@newtonlabs.com Tue Jun 10 00:49:54 2003 From: cwitty@newtonlabs.com (Carl R. Witty) Date: 09 Jun 2003 16:49:54 -0700 Subject: on termination In-Reply-To: "Cagdas Ozgenc"'s message of "Thu, 8 May 2003 09:05:25 +0300" References: <02d301c31527$d59649d0$63968cc1@ozgenc> Message-ID: "Cagdas Ozgenc" writes: > This may be a little off topic, but I could not get much response from = > comp.theory, so here it goes: > > Is it possible to have a programming language that can be used to = > produce only the programs that terminate, but at the same time decide = > all recursive languages? Or does such limitation automatically reduce = > the class of languages that such a programming language decide to = > primitive-recursive? If you have any programming language (say Haskell), and if you have some formal system which is capable of proving termination properties of programs in your programming language (and in which proofs are machine-checkable), then you can create a new language "Terminating Haskell" simply by pairing each program with a proof of termination. Of course, if you start with a Turing-complete language, then your formal system is necessarily incomplete; this means there will be programs that do terminate but that you cannot prove terminate. So your programming language will include programs that decide all languages that you can prove recursive (in your formal system), but not all recursive languages. However, if your formal system is strong enough, it may be possible to prove termination of all the programs you really care about. Some theorem-proving systems (including ACL2 and PVS) are like this -- within the logic, you can write programs in a Turing-complete language, as long as you can prove termination. (More precisely, the language would be Turing-complete were it not for the termination requirement. In both cases, the "program" portion is fairly distinct from the "proof of termination" portion, so that it does make sense to talk about what the language would be like without the termination requirement.) It has long been a goal of mine to create a Haskell-like programming language where you could mark portions as being guaranteed to terminate. The compiler would prove termination whenever it could, but in cases where the termination proof was too complicated for automatic proofs, the programmer would be required to add an explicit proof of termination. Carl Witty From escuta21@bol.com.br Tue Jun 10 03:49:53 2003 From: escuta21@bol.com.br (kandrak) Date: Tue, 10 Jun 2003 02:49:53 Subject: Bom dia haskell-cafe Message-ID: <20030610054953.E8A66421EEB@www.haskell.org> Message to haskell-cafe@haskell.org Ola!!!! haskell-cafe GANHAMOS O PRĘMIO DE MELHOR SITE DO RAMO ======Estamos operando em Novo Formato====== Confira em: escuta21.kit.net ou http://www.escuta21.kit.net ei.... haskell-cafe Cuidado com o que fala ao Celular... ele tb tem ouvidos... para remover o haskell-cafe@haskell.org de nossa lista responda este e-mail e coloque remover nos perdoe o transtorno...ok? kandrak From oleg@pobox.com Tue Jun 10 09:34:40 2003 From: oleg@pobox.com (oleg@pobox.com) Date: Tue, 10 Jun 2003 01:34:40 -0700 (PDT) Subject: Powerset Message-ID: <200306100834.h5A8Ye0u026939@adric.fnmoc.navy.mil> The following seems to be a faster version of powerset that delivers results strictly in the order of increasing cardinality (i.e., all sets of size 1 first, then of size 2, etc). It seems to run faster than any other ordered version of powerset posted so far. On GHCi, length $ powerset [1..22] is computed roughly 4 times faster than powerset3 given earlier. On Hugs, the powerset below also runs faster, with less memory consumption and in fewer GC cycles, up to a limit of 18 for the size of the input set. Then something happens. length $ powerset3 [1..19] runs out of memory on my (not current) version of Hugs too. The algorithm is more complex, though. Suppose we have a list xs Let powerset_n xs = filter (\p -> length p == n) $ powerset xs Let ps n i = powerset_n $ (tails xs)!!i that is, ps n 0 = powerset_n xs ps n (length(xs)-n) = [(tails xs)!!(length(xs)-n)] that is, i varies from 0 to (length(xs)-n) We observe that ps n (i-1) = ps n i ++ (map (x:) $ ps (n-1) i) where x = xs!!(i-1) Therefore, if we know ps (n-1) i for all i, we can compute ps n i from the base condition ps n (length(xs)-n) = [(tails xs)!!(length(xs)-n)] and then decrementing i. This recurrence is the instance of the right fold psn n psn1 = foldr (\ (psn1i,x) ps@(psni:_) -> (psni ++ (map(x:) psn1i)):ps) [[(tails xs)!!(length(xs)-n)]] $ zip (tail$init psn1) xs We can build ps n from n=0 onwards, given that ps 0 = map (const [[]]) (tails xs) we then observe that (tails xs)!!(length(xs)-n) === (reverse $ tails xs) !! n which, after a few simplifications, gives us import List powerset [] = [[]] powerset [x] = [[],[x]] powerset xs = [] : runit (tail rsxtails) ps0 where xstails = tails xs rsxtails = reverse xstails ps0 = map (const [[]]) $ tail xstails psn tn psn1 = foldr (\ xpsn1i ps@(psni:_) -> (xpsn1i++psni):ps) [[tn]] $ zipWith (\x psn1i -> map (x:) psn1i) xs (init $ psn1) runit [tn] _ = [xs] runit (tn:tns) psn1 = newps0 ++ (runit tns newps) where (newps0:newps) = psn tn psn1 There is still some room for improvement left. Actually, the following is a slightly faster version, showing off lazy evaluation: powerset [] = [[]] powerset [x] = [[],[x]] powerset xs = [] : runit (tail rsxtails) ps0 where xstails = tails xs rsxtails = reverse xstails ps0 = map (const [[]]) xstails psn tn psn1 = psnew where psnew = [tn]: (zipWith (++) (reverse (zipWith (\x psn1i -> map (x:) psn1i) xs (tail $ reverse$tail $ psn1))) psnew) runit [tn] _ = [xs] runit (tn:tns) psn1 = (last newps) ++ (runit tns newps) where newps = psn tn psn1 From simonmar@microsoft.com Tue Jun 10 12:10:26 2003 From: simonmar@microsoft.com (Simon Marlow) Date: Tue, 10 Jun 2003 12:10:26 +0100 Subject: Compiling hws with ghc 6 Message-ID: <9584A4A864BD8548932F2F88EB30D1C60D33E9CF@TVP-MSG-01.europe.corp.microsoft.com> =20 > I'm trying to compile the haskell web server (from the=20 > haskell-libs project=20 > at sf.net) with ghc6 and I'm stuck on the last function in Util.hs: >=20 > statMaybe filename =3D do > maybe_stat <- tryJust ioErrors (getFileStatus filename) > case maybe_stat of > Left e -> do > errno <- getErrorCode > if errno =3D=3D eNOENT > then return Nothing > else ioError e > Right stat -> > return (Just stat) >=20 >=20 > What are the equivalents for getFileStatus and getErrorCode=20 > these days? > > I suppose Foreign.C.Error.getErrno might substitute for=20 > getErrorCode, but I'm stumped on getFileStatus. You're right about getErrno. getFileStatus is available from System.Posix. Cheers, Simon From simonmar@microsoft.com Tue Jun 10 12:14:35 2003 From: simonmar@microsoft.com (Simon Marlow) Date: Tue, 10 Jun 2003 12:14:35 +0100 Subject: Powerset Message-ID: <9584A4A864BD8548932F2F88EB30D1C60D33E9D6@TVP-MSG-01.europe.corp.microsoft.com> =20 > The following seems to be a faster version of powerset that delivers > results strictly in the order of increasing cardinality (i.e., all > sets of size 1 first, then of size 2, etc). It seems to run faster > than any other ordered version of powerset posted so far. On GHCi, > length $ powerset [1..22] is computed roughly 4 times faster than > powerset3 given earlier. On Hugs, the powerset below also runs faster, > with less memory consumption and in fewer GC cycles, up to a limit of > 18 for the size of the input set. Just a word of warning: using GHCi or Hugs for comparison benchmarking will give unreliable results. Use GHC with -O. Cheers, Simon From maeder@tzi.de Tue Jun 10 13:53:16 2003 From: maeder@tzi.de (Christian Maeder) Date: Tue, 10 Jun 2003 14:53:16 +0200 Subject: Powerset In-Reply-To: <200306100834.h5A8Ye0u026939@adric.fnmoc.navy.mil> References: <200306100834.h5A8Ye0u026939@adric.fnmoc.navy.mil> Message-ID: <3EE5D4BC.9040808@tzi.de> powerset :: [a] -> [[[a]]] powerset [] = [[[]]] powerset (x:xs) = [[]] : myzip x (powerset xs) myzip :: a -> [[[a]]] -> [[[a]]] myzip x [a] = [map (x:) a] myzip x (a:b) = (map (x:) a ++ head b) : myzip x b I suggest the above version for a sorted powerset. The result keeps a further nesting of lists for subsets of the same length. (Flatten this list with "concat".) Call "length (concat (powerset [1..19]))" (on Hugs). Christian oleg@pobox.com wrote: > The following seems to be a faster version of powerset that delivers > results strictly in the order of increasing cardinality (i.e., all > sets of size 1 first, then of size 2, etc). It seems to run faster > than any other ordered version of powerset posted so far. On GHCi, > length $ powerset [1..22] is computed roughly 4 times faster than > powerset3 given earlier. On Hugs, the powerset below also runs faster, > with less memory consumption and in fewer GC cycles, up to a limit of > 18 for the size of the input set. Then something happens. length $ > powerset3 [1..19] runs out of memory on my (not current) version of > Hugs too. > > The algorithm is more complex, though. > powerset [] = [[]] > powerset [x] = [[],[x]] > powerset xs = [] : runit (tail rsxtails) ps0 > where > xstails = tails xs > rsxtails = reverse xstails > ps0 = map (const [[]]) xstails > psn tn psn1 = psnew > where > psnew = [tn]: > (zipWith (++) > (reverse (zipWith (\x psn1i -> map (x:) psn1i) xs (tail $ reverse$tail $ psn1))) > psnew) > > runit [tn] _ = [xs] > runit (tn:tns) psn1 = (last newps) ++ (runit tns newps) > where newps = psn tn psn1 > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe > From GK@ninebynine.org Tue Jun 10 21:14:22 2003 From: GK@ninebynine.org (Graham Klyne) Date: Tue, 10 Jun 2003 21:14:22 +0100 Subject: Powerset In-Reply-To: <3EE5D4BC.9040808@tzi.de> References: <200306100834.h5A8Ye0u026939@adric.fnmoc.navy.mil> <200306100834.h5A8Ye0u026939@adric.fnmoc.navy.mil> Message-ID: <5.1.0.14.2.20030610211303.02fc5bc0@127.0.0.1> That's very similar to a version I received in an offlist email, which I had been seeking permission to repost. I find this approach to be very elegant. #g -- At 14:53 10/06/03 +0200, Christian Maeder wrote: >powerset :: [a] -> [[[a]]] >powerset [] = [[[]]] >powerset (x:xs) = [[]] : myzip x (powerset xs) > >myzip :: a -> [[[a]]] -> [[[a]]] >myzip x [a] = [map (x:) a] >myzip x (a:b) = (map (x:) a ++ head b) : myzip x b > >I suggest the above version for a sorted powerset. The result keeps a >further nesting of lists for subsets of the same length. (Flatten this >list with "concat".) > >Call "length (concat (powerset [1..19]))" (on Hugs). > >Christian > >oleg@pobox.com wrote: >>The following seems to be a faster version of powerset that delivers >>results strictly in the order of increasing cardinality (i.e., all >>sets of size 1 first, then of size 2, etc). It seems to run faster >>than any other ordered version of powerset posted so far. On GHCi, >>length $ powerset [1..22] is computed roughly 4 times faster than >>powerset3 given earlier. On Hugs, the powerset below also runs faster, >>with less memory consumption and in fewer GC cycles, up to a limit of >>18 for the size of the input set. Then something happens. length $ >>powerset3 [1..19] runs out of memory on my (not current) version of >>Hugs too. >>The algorithm is more complex, though. >>powerset [] = [[]] >>powerset [x] = [[],[x]] >>powerset xs = [] : runit (tail rsxtails) ps0 >> where >> xstails = tails xs >> rsxtails = reverse xstails >> ps0 = map (const [[]]) xstails >> psn tn psn1 = psnew >> where >> psnew = [tn]: >> (zipWith (++) >> (reverse (zipWith (\x psn1i -> map (x:) psn1i) xs (tail $ >> reverse$tail $ psn1))) >> psnew) >> runit [tn] _ = [xs] >> runit (tn:tns) psn1 = (last newps) ++ (runit tns newps) >> where newps = psn tn psn1 >>_______________________________________________ >>Haskell-Cafe mailing list >>Haskell-Cafe@haskell.org >>http://www.haskell.org/mailman/listinfo/haskell-cafe > > >_______________________________________________ >Haskell-Cafe mailing list >Haskell-Cafe@haskell.org >http://www.haskell.org/mailman/listinfo/haskell-cafe ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From d00ram@dtek.chalmers.se Tue Jun 10 21:19:57 2003 From: d00ram@dtek.chalmers.se (Hampus Ram) Date: Tue, 10 Jun 2003 22:19:57 +0200 Subject: Haskell.org out of date Message-ID: <20030610201957.GA16028@persephone.dtek.chalmers.se> Who takes care of haskell.org? If it is the "community" we're obviously not doing it right, lots of broken links and some that is there but does not work (e.g. the wish-list). Only the "libraries and tools" page contains 16 broken links (according to linkchecker.sf.net) and some of the tools should in my opinion be marked clearly with "antique" so you do not get upset when they require ghc 2 to compile without problem... /Hampus - (I can't decide where it's best to post this...) -- Homepage: http://www.dtek.chalmers.se/~d00ram E-mail: d00ram@dtek.chalmers.se "Det är aldrig försent att ge upp" From claus.reinke@talk21.com Tue Jun 10 22:11:42 2003 From: claus.reinke@talk21.com (Claus Reinke) Date: Tue, 10 Jun 2003 22:11:42 +0100 Subject: Haskell.org out of date References: <20030610201957.GA16028@persephone.dtek.chalmers.se> Message-ID: <003801c32f94$e4dd9ce0$9d548351@Standard> > Who takes care of haskell.org? You. And that means not just Hampus, but all of us reading this. See also the bottom of haskell.org, or the latest of the regular calls for help by the current site maintainers, in last month's HC&AR (which is one project intended to help with this problem): http://haskell.cs.yale.edu/communities/05-2003/html/report.html#sect1.1 I assume you knew about all this, and the intent of your email was to send a wake-up call to all readers of this list before going on to doing your own bit (which can be as small as finding some specific out-of-date info, googling for the current link if any, and sending the diff to John and Olaf, or as big as taking charge of the part of haskell.org that most interests you and coming up with a system that makes maintenance easy;-). Good idea!-) Whenever anyone finds something odd about your haskell.org: just do something about it (preferably something that helps;-)! Cheers, Claus (who now wanders off to see whether there are any links to his own pages from haskell.org that would need updating!-) > If it is the "community" we're obviously not doing it right, lots of > broken links and some that is there but does not work (e.g. the wish-list). > Only the "libraries and tools" page contains 16 broken links (according > to linkchecker.sf.net) and some of the tools should in my opinion be > marked clearly with "antique" so you do not get upset when they require > ghc 2 to compile without problem... > > /Hampus - (I can't decide where it's best to post this...) > > -- > Homepage: http://www.dtek.chalmers.se/~d00ram > E-mail: d00ram@dtek.chalmers.se > > "Det är aldrig försent att ge upp" > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe > From hallgren@cse.ogi.edu Wed Jun 11 00:54:09 2003 From: hallgren@cse.ogi.edu (Thomas Hallgren) Date: Tue, 10 Jun 2003 16:54:09 -0700 Subject: Fudgets In-Reply-To: References: <3EE362AE.9020100@gmx.net> <3EE3739A.3060800@cse.ogi.edu> Message-ID: <3EE66FA1.4080609@cse.ogi.edu> Ashley Yakeley wrote: > Would it be worth rewriting Fudgets to take advantage of such recent > advances in Haskell as monadic IO? A rejuvenation of Fudgets, taking advantage of things like subtyping, multi-parameter classes with functional dependencies, syntactic sugar for arrows, making room for monadic IO, and using a more modern graphics subsystem, would probably make Fudgets much more interesting. Actually, Fruit [1], although it is independent work, could be seen as a redesign/rejuvenation of Fudgets. Allowing arbitrary monadic IO inside fudgets is not impossible, see [2], but while it would give access to modern things like the FFI, it would also mean giving up some of the purity and elegance of fudgets. The old approach to IO, where every IO operation is a constructor in a data type, means that all IO operations can be examined and manipulated within the program in interesting ways, by just adding a wrapper around the main function. For example, when a fudget program is run with the -debug flag, a trace of all IO operations and their results is printed on stderr. As another example, the cacheF fudget wrapper speeds up fudget programs by caching the result of requests for colors, fonts and other GUI resources. It would be easy to write a wrapper that swaps the left and right mouse buttons, or makes a program ask for the user's permission before deleting a file. Try doing things like that by adding a wrapper around a value of type IO()! >I must confess I'm not all that familiar with Fudgets, although it >certainly looks interesting. For what sort of problems is it currently >the best solution? > I guess it depends on what you are comparing to, but if you like programming GUIs in a declarative style, you don't need the FFI but can live with the IO operations already provided by the fudget library (which includes file/directory access and networking), or perhaps you want to experiment with implementing your own special purpose widgets in Haskell (Fudgets implements its own widget set in Haskell), then using Fudgets might be a good choice. But when the GUI starts getting big and irregular, the plumbing can become a bit clumpsy (some would even say painful, "worse than having a tooth pulled" :-). -- Thomas H [1] http://www.haskell.org/fruit [2] http://www.cs.chalmers.se/~hallgren/Thesis/fudgets-implementation.html#fudgets-on-monadIO From m.p.donadio@ieee.org Wed Jun 11 02:59:22 2003 From: m.p.donadio@ieee.org (Matthew Donadio) Date: Tue, 10 Jun 2003 21:59:22 -0400 Subject: Haskell.org out of date References: <20030610201957.GA16028@persephone.dtek.chalmers.se> Message-ID: <3EE68CFA.D4EFE14D@ieee.org> Hampus Ram wrote: > If it is the "community" we're obviously not doing it right, lots of > broken links and some that is there but does not work (e.g. the wish-list). > Only the "libraries and tools" page contains 16 broken links (according > to linkchecker.sf.net) and some of the tools should in my opinion be > marked clearly with "antique" so you do not get upset when they require > ghc 2 to compile without problem... Well, I will say that John and Olaf have taken care of my updates within a few hours. The Haskell Community Report lists what projects are active and what the status is. If you see a problem on the website, just metion it any someone will take care of it. -- Matthew Donadio (m.p.donadio@ieee.org) From GK@ninebynine.org Wed Jun 11 08:37:48 2003 From: GK@ninebynine.org (Graham Klyne) Date: Wed, 11 Jun 2003 08:37:48 +0100 Subject: Non-determinism, backtracking and Monads In-Reply-To: <3EDF0810.1040701@info.unicaen.fr> References: <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604214132.033fc090@127.0.0.1> Message-ID: <5.1.0.14.2.20030608090933.024397a8@127.0.0.1> At 11:06 05/06/03 +0200, Jerzy Karczmarczuk wrote: >I permit myself to observe that your powerset problem (and the restricted >length problem, i.e. the combinations) is usually solved in Prolog, through >backtracking, using reasoning/style which adopts this "individualistic" >philosophy. > >powerset(,) --- is the pattern. And the >solution is > >powerset([],[]). Since nothing else can be done. Otherwise you pick the item > or not. > >powerset([X|Rest],L) :- powerset(Rest,L). >powerset([X|Rest],[X|L) :- powerset(Rest,L). > >The xxx ++ map (x :) xxx solution in Haskell is a particular formulation >(and optimization) of the straightforward transformation from a version >using the non-deterministic Monad. This one is really almost a carbon copy >of the Prolog solution, with appropriate "lifting" of operations from >individuals to lazy lists. I was thinking some more about this comment of yours, and my own experience with the ease of using lists to implement prolog-style generators, and think I come to some better understanding. If I'm right, I assume the following is common knowledge to experienced Haskell programmers. So, in the spirit of testing my understanding... The common thread here is a non-deterministic calculation in which there are several possible solutions for some problem. The goal is to find (a) if there are any solutions, and (b) one, more or all of the solutions. Prolog does this, absent ! (cut), by backtracking through the possible solutions. My first epiphany is that the Haskell idea of using a lazily evaluated list for result of a non-deterministic computation is pretty much the same thing (which is pretty much what you said? Is this what you mean by "the non-deterministic monad"?). The mechanisms for accessing a list mean that the solutions must be accessed in the order they are generated, just like Prolog backtracking. So there seems to be a very close relationship between the lazy list and non-deterministic computations, but what about other data structures? I speculate that other structures, lazily evaluated, may also be used to represent the results of non-deterministic computations, yet allow the results to be accessed in a different order. And these, too, may be (should be?) monads. If so, the Haskell approach might be viewed as a generalization of Prolog's essentially sequential backtracking. In a private message concerning the powerset thread on this list, a correspondent offered a program to evaluate the subsets in size order, which I found particularly elegant: >ranked_powerset :: [a] -> [[[a]]] >ranked_powerset = takeWhile (not . null) . foldr next_powerset ([[]] : repeat []) > >next_powerset :: a -> [[[a]]] -> [[[a]]] >next_powerset x r = zipWith (++) ([] : map (map (x:)) r) r > >powerset :: [a] -> [[a]] >powerset = tail . concat . ranked_powerset They also pointed out that "ranked_powerset is handy since you can use it to define combinatorial choice etc.": > choose :: Int -> [a] -> [[a]] > choose k = (!! k) . ranked_powerset So here is an example of a different structure (a list of lists) also used to represent a non-deterministic computation, and furthermore providing means to access the results in some order other than a single linear sequences (e.g. could be used to enumerate all the powersets containing the nth member of the base set, *or* all the powersets of a given size, without evaluating all of the other powersets). To test this idea, I think it should be possible to define a monad based on a simple tree structure, which also can be used to represent the results of a non-deterministic computation. An example of this is below, at the end of this message, which seems to exhibit the expected properties. So if the idea of representing a non-deterministic computation can be generalized from a list to a tree, why not to other data structures? My tree monad is defined wholly in terms of reduce and fmap. Without going through the exercise, I think the reduce function might be definable in terms of fmap for any data type of the form "Type (Maybe a)", hence applicable to a range of functors? In particular, I'm wondering if it can be applied to any gmap-able structure over a Maybe type. I'm not sure if this is of any practical use; rather it's part of my attempts to understand the relationship between functors and monads and other things functional. #g -- [[ -- spike-treemonad.hs data Tree a = L (Maybe a) | T { l,r :: Tree a } deriving Eq instance (Show a) => Show (Tree a) where show t = (showTree "" t) ++ "\n" showTree :: (Show a) => String -> Tree a -> String showTree _ (L Nothing ) = "()" showTree _ (L (Just a)) = show a showTree i (T l r) = "( " ++ (showTree i' l) ++ "\n" ++ i' ++ (showTree i' r) ++ " )" where i' = ' ':' ':i instance Functor Tree where fmap f (L Nothing) = L Nothing fmap f (L (Just a)) = L (Just (f a)) fmap f (T l r) = T (fmap f l) (fmap f r) reduce :: Tree (Tree a) -> Tree a reduce (L Nothing) = L Nothing reduce (L (Just (L Nothing ) )) = L Nothing reduce (L (Just (L (Just a)) )) = L (Just a) reduce (L (Just (T l r ) )) = T l r reduce (T l r) = T (reduce l) (reduce r) instance Monad Tree where -- L Nothing >>= k = L Nothing t >>= k = reduce $ fmap k t return x = L (Just x) fail s = L Nothing -- tests t1 :: Tree String t1 = T (L $ Just "1") (T (T (T (L $ Just "211") (L $ Just "311")) (L Nothing)) (L $ Just "22")) k1 :: a -> Tree a k1 n = T (L $ Just n) (L $ Just n) r1 = t1 >>= k1 k2 :: String -> Tree String k2 s@('1':_) = L $ Just s k2 s@('2':_) = T (L $ Just s) (L $ Just s) k2 _ = L Nothing r2 = t1 >>= k2 t3 = L Nothing :: Tree String r3 = t3 >>= k1 r4 = t1 >>= k1 >>= k2 r5 = (return "11") :: Tree String r6 = r5 >>= k1 -- Check out monad laws -- return a >>= k = k a m1a = (return t1) >>= k1 m1b = k1 t1 m1c = m1a == m1b -- m >>= return = m m2a = t1 >>= return m2b = t1 m2c = m2a == m2b -- m >>= (\x -> k x >>= h) = (m >>= k) >>= h m3a = t1 >>= (\x -> k1 x >>= k2) m3b = (t1 >>= k1) >>= k2 m3c = m3a == m3b ]] ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From ajb@spamcop.net Wed Jun 11 09:02:30 2003 From: ajb@spamcop.net (Andrew J Bromage) Date: Wed, 11 Jun 2003 18:02:30 +1000 Subject: Non-determinism, backtracking and Monads In-Reply-To: <5.1.0.14.2.20030608090933.024397a8@127.0.0.1> References: <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604214132.033fc090@127.0.0.1> <5.1.0.14.2.20030608090933.024397a8@127.0.0.1> Message-ID: <20030611080230.GA8264@smtp.alicorna.com> G'day all. On Wed, Jun 11, 2003 at 08:37:48AM +0100, Graham Klyne wrote: > I was thinking some more about this comment of yours, and my own experience > with the ease of using lists to implement prolog-style generators, and > think I come to some better understanding. You might find this amusing: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/hfl/hfl/mtl/Logic.hs?rev=1.2 This monad and monad transformer basically implement ground-moded logic programming, including if-then-else with soft cut. (It doesn't implement Prolog cut, but you really don't want it.) > So there seems to be a very close relationship between the lazy list and > non-deterministic computations, but what about other data structures? I > speculate that other structures, lazily evaluated, may also be used to > represent the results of non-deterministic computations, yet allow the > results to be accessed in a different order. Yes. The different data structures would, in general I think, correspond to different search rules. Using a lazy list corresponds to depth-first search. Your tree monad actually returns the entire computation tree, which can then be traversed in depth-first order, breadth-first order, or whatever order you want. You have to be careful with monad transformers stacked on top of non-commutative monads, though. Most programmers would expect, in this code: (lift m1 `mplus` lift m2) `mplus` lift m3 that both m1 and m2 will be evaluated before m3; at least in circumstances where it mattered. Cheers, Andrew Bromage From simonpj@microsoft.com Wed Jun 11 09:03:32 2003 From: simonpj@microsoft.com (Simon Peyton-Jones) Date: Wed, 11 Jun 2003 09:03:32 +0100 Subject: Non-determinism, backtracking and Monads Message-ID: Check out "Embedding Prolog in Haskell", which explores exactly the topic you discuss. http://citeseer.nj.nec.com/272378.html Simon | -----Original Message----- | From: haskell-cafe-admin@haskell.org [mailto:haskell-cafe-admin@haskell.org] On Behalf Of Graham | Klyne | Sent: 11 June 2003 08:38 | To: Jerzy Karczmarczuk; Haskell Cafe | Subject: Non-determinism, backtracking and Monads |=20 | At 11:06 05/06/03 +0200, Jerzy Karczmarczuk wrote: | >I permit myself to observe that your powerset problem (and the restricted | >length problem, i.e. the combinations) is usually solved in Prolog, through | >backtracking, using reasoning/style which adopts this "individualistic" | >philosophy. | > | >powerset(,) --- is the pattern. And the | >solution is | > | >powerset([],[]). Since nothing else can be done. Otherwise you pick the item | > or not. | > | >powerset([X|Rest],L) :- powerset(Rest,L). | >powerset([X|Rest],[X|L) :- powerset(Rest,L). | > | >The xxx ++ map (x :) xxx solution in Haskell is a particular formulation | >(and optimization) of the straightforward transformation from a version | >using the non-deterministic Monad. This one is really almost a carbon copy | >of the Prolog solution, with appropriate "lifting" of operations from | >individuals to lazy lists. |=20 | I was thinking some more about this comment of yours, and my own experience | with the ease of using lists to implement prolog-style generators, and | think I come to some better understanding. If I'm right, I assume the | following is common knowledge to experienced Haskell programmers. So, in | the spirit of testing my understanding... |=20 | The common thread here is a non-deterministic calculation in which there | are several possible solutions for some problem. The goal is to find (a) | if there are any solutions, and (b) one, more or all of the solutions. |=20 | Prolog does this, absent ! (cut), by backtracking through the possible | solutions. |=20 | My first epiphany is that the Haskell idea of using a lazily evaluated list | for result of a non-deterministic computation is pretty much the same thing | (which is pretty much what you said? Is this what you mean by "the | non-deterministic monad"?). The mechanisms for accessing a list mean that | the solutions must be accessed in the order they are generated, just like | Prolog backtracking. |=20 | So there seems to be a very close relationship between the lazy list and | non-deterministic computations, but what about other data structures? I | speculate that other structures, lazily evaluated, may also be used to | represent the results of non-deterministic computations, yet allow the | results to be accessed in a different order. And these, too, may be | (should be?) monads. If so, the Haskell approach might be viewed as a | generalization of Prolog's essentially sequential backtracking. |=20 | In a private message concerning the powerset thread on this list, a | correspondent offered a program to evaluate the subsets in size order, | which I found particularly elegant: |=20 | >ranked_powerset :: [a] -> [[[a]]] | >ranked_powerset =3D takeWhile (not . null) . foldr next_powerset = ([[]] : | repeat []) | > | >next_powerset :: a -> [[[a]]] -> [[[a]]] | >next_powerset x r =3D zipWith (++) ([] : map (map (x:)) r) r | > | >powerset :: [a] -> [[a]] | >powerset =3D tail . concat . ranked_powerset |=20 | They also pointed out that "ranked_powerset is handy since you can use it | to define combinatorial choice etc.": |=20 | > choose :: Int -> [a] -> [[a]] | > choose k =3D (!! k) . ranked_powerset |=20 | So here is an example of a different structure (a list of lists) also used | to represent a non-deterministic computation, and furthermore providing | means to access the results in some order other than a single linear | sequences (e.g. could be used to enumerate all the powersets containing the | nth member of the base set, *or* all the powersets of a given size, without | evaluating all of the other powersets). |=20 | To test this idea, I think it should be possible to define a monad based on | a simple tree structure, which also can be used to represent the results of | a non-deterministic computation. An example of this is below, at the end | of this message, which seems to exhibit the expected properties. |=20 | So if the idea of representing a non-deterministic computation can be | generalized from a list to a tree, why not to other data structures? My | tree monad is defined wholly in terms of reduce and fmap. Without going | through the exercise, I think the reduce function might be definable in | terms of fmap for any data type of the form "Type (Maybe a)", hence | applicable to a range of functors? In particular, I'm wondering if it can | be applied to any gmap-able structure over a Maybe type. |=20 | I'm not sure if this is of any practical use; rather it's part of my | attempts to understand the relationship between functors and monads and | other things functional. |=20 | #g | -- |=20 |=20 | [[ | -- spike-treemonad.hs |=20 | data Tree a =3D L (Maybe a) | T { l,r :: Tree a } | deriving Eq |=20 | instance (Show a) =3D> Show (Tree a) where | show t =3D (showTree "" t) ++ "\n" |=20 | showTree :: (Show a) =3D> String -> Tree a -> String | showTree _ (L Nothing ) =3D "()" | showTree _ (L (Just a)) =3D show a | showTree i (T l r) =3D "( " ++ (showTree i' l) ++ "\n" ++ | i' ++ (showTree i' r) ++ " )" | where i' =3D ' ':' ':i |=20 | instance Functor Tree where | fmap f (L Nothing) =3D L Nothing | fmap f (L (Just a)) =3D L (Just (f a)) | fmap f (T l r) =3D T (fmap f l) (fmap f r) |=20 | reduce :: Tree (Tree a) -> Tree a | reduce (L Nothing) =3D L Nothing | reduce (L (Just (L Nothing ) )) =3D L Nothing | reduce (L (Just (L (Just a)) )) =3D L (Just a) | reduce (L (Just (T l r ) )) =3D T l r | reduce (T l r) =3D T (reduce l) (reduce r) |=20 | instance Monad Tree where | -- L Nothing >>=3D k =3D L Nothing | t >>=3D k =3D reduce $ fmap k t | return x =3D L (Just x) | fail s =3D L Nothing |=20 | -- tests |=20 | t1 :: Tree String | t1 =3D T (L $ Just "1") | (T (T (T (L $ Just "211") | (L $ Just "311")) | (L Nothing)) | (L $ Just "22")) |=20 | k1 :: a -> Tree a | k1 n =3D T (L $ Just n) (L $ Just n) |=20 | r1 =3D t1 >>=3D k1 |=20 | k2 :: String -> Tree String | k2 s@('1':_) =3D L $ Just s | k2 s@('2':_) =3D T (L $ Just s) (L $ Just s) | k2 _ =3D L Nothing |=20 | r2 =3D t1 >>=3D k2 |=20 | t3 =3D L Nothing :: Tree String | r3 =3D t3 >>=3D k1 |=20 | r4 =3D t1 >>=3D k1 >>=3D k2 | r5 =3D (return "11") :: Tree String | r6 =3D r5 >>=3D k1 |=20 | -- Check out monad laws | -- return a >>=3D k =3D k a | m1a =3D (return t1) >>=3D k1 | m1b =3D k1 t1 | m1c =3D m1a =3D=3D m1b |=20 | -- m >>=3D return =3D m | m2a =3D t1 >>=3D return | m2b =3D t1 | m2c =3D m2a =3D=3D m2b |=20 | -- m >>=3D (\x -> k x >>=3D h) =3D (m >>=3D k) >>=3D h | m3a =3D t1 >>=3D (\x -> k1 x >>=3D k2) | m3b =3D (t1 >>=3D k1) >>=3D k2 | m3c =3D m3a =3D=3D m3b | ]] |=20 |=20 | ------------------- | Graham Klyne | | PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E |=20 | _______________________________________________ | Haskell-Cafe mailing list | Haskell-Cafe@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-cafe From karczma@info.unicaen.fr Wed Jun 11 11:36:30 2003 From: karczma@info.unicaen.fr (Jerzy Karczmarczuk) Date: Wed, 11 Jun 2003 12:36:30 +0200 Subject: Non-determinism, backtracking and Monads References: <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604214132.033fc090@127.0.0.1> <5.1.0.14.2.20030608090933.024397a8@127.0.0.1> Message-ID: <3EE7062E.5000605@info.unicaen.fr> Graham Klyne wrote on the subject of powerset through backtracking: > > The common thread here is a non-deterministic calculation in which there > are several possible solutions for some problem. The goal is to find > (a) if there are any solutions, and (b) one, more or all of the solutions. > > Prolog does this, absent ! (cut), by backtracking through the possible > solutions. > > My first epiphany is that the Haskell idea of using a lazily evaluated > list for result of a non-deterministic computation is pretty much the > same thing (which is pretty much what you said? Is this what you mean > by "the non-deterministic monad"?). The mechanisms for accessing a list > mean that the solutions must be accessed in the order they are > generated, just like Prolog backtracking. Yes. I didn't invent any wheel, just pointed out that in these cases the remark "easier to say than to do" is too sad. The translation from Prolog may be really automatic, although the simple-minded result is polluted with (++) and concat. > So there seems to be a very close relationship between the lazy list and > non-deterministic computations, but what about other data structures? I > speculate that other structures, lazily evaluated, may also be used to > represent the results of non-deterministic computations, yet allow the > results to be accessed in a different order. And these, too, may be > (should be?) monads. Of course, one can produce lazy trees and other plexes. Most of them are naturally Functors, but in the general case I am not sure whether there is a natural way to implement >>= for any shape... === On the other hand there is a Monadic Niche elsewhere which is *very different* from the manipulation of lazy lists, and yet may be used for similar purposes. I mean: the continuation business. It is possible, instead of implementing the *data backtracking* through lazy lists, to make lazy "backtrackable" continuations, permitting to redirect the flow of control to produce something else. The two ways are - perhaps not entirely equivalent, but essentially two orchestrations of the same theme. I lost my references, perhaps somebody?... Jerzy Karczmarczuk From diatchki@cse.ogi.edu Wed Jun 11 13:10:41 2003 From: diatchki@cse.ogi.edu (Iavor Diatchki) Date: Wed, 11 Jun 2003 05:10:41 -0700 (PDT) Subject: Non-determinism, backtracking and Monads Message-ID: <33312.212.36.8.85.1055333441.squirrel@webmail.cse.ogi.edu> hello, you might also want to take a look at the "new monad library" i am working on. it is based on the old one, but does some things slightly different. one of the differences is the "nondeterminism transformer" whose implementation is inbetween lists and continuations. it also resembles resumptions quite a bit. i came up with this particular implementation but i would not be surprised if people already know about it. it is also quite simillar to the "term implementation" of the backtracking transformer described by ralf heinze in his "deriving monad transformers" paper. i would also be interested in general comments on the library. it is in the haskell cvs repository in fptools/libraries/monads (you need to check out fpconfig frist). bye iavor From ddarius@hotpop.com Wed Jun 11 19:04:35 2003 From: ddarius@hotpop.com (Derek Elkins) Date: Wed, 11 Jun 2003 14:04:35 -0400 Subject: Non-determinism, backtracking and Monads In-Reply-To: References: Message-ID: <20030611140435.000078b3.ddarius@hotpop.com> On Wed, 11 Jun 2003 09:03:32 +0100 "Simon Peyton-Jones" wrote: > Check out "Embedding Prolog in Haskell", which explores exactly the > topic you discuss. > > http://citeseer.nj.nec.com/272378.html > > Simon and what can be considered a followup to that paper, http://citeseer.nj.nec.com/claessen00typed.html -- solve (do (x,y) <- free; append x y (s2l "abc"); -- liftM2 (,) (list atom x) (list atom y)) ==> -- ([],["a","b","c"]),(["a"],["b","c"]),(["a","b"],["c"]),(["a","b","c"],[ ]) append :: (Unify s a, Free s a) => List s a -> List s a -> List s a -> LP s () append ps qs rs = (do ps =:= Nil qs =:= rs) `mplus` (do (x,xs,ys) <- free ps =:= (x ::: xs) rs =:= (x ::: ys) append xs qs ys) -- append([],L,L). -- append([H|T],L,[H|Rest]) :- append(T,L,Rest). powerset' xs ys = free >>= \(h,t,rest) -> p2h [ [xs =:= Nil, ys =:= Nil], [xs =:= (h ::: t), powerset' t ys], [xs =:= (h ::: t), ys =:= (h ::: rest), powerset' t rest]] -- powerset([],[]). -- powerset([X|Xs],Rest) :- powerset(Xs,Rest) -- powerset([X|Xs],[X|Rest]) :- powerset(Xs,Rest). From claus.reinke@talk21.com Wed Jun 11 23:37:43 2003 From: claus.reinke@talk21.com (Claus Reinke) Date: Wed, 11 Jun 2003 23:37:43 +0100 Subject: Haskell.org out of date References: <20030610201957.GA16028@persephone.dtek.chalmers.se> <003801c32f94$e4dd9ce0$9d548351@Standard> Message-ID: <00d501c3306a$1456b800$ae1ffea9@Standard> > .. doing your own bit (which can be as small as finding some > specific out-of-date info, googling for the current link if any, and > sending the diff to John and Olaf, or as big as taking charge of > the part of haskell.org that most interests you and coming up > with a system that makes maintenance easy;-). Good idea!-) > > Whenever anyone finds something odd about your haskell.org: > just do something about it (preferably something that helps;-)! for illustration: following Hampus' email, I fed the libraries and tools url into http://validator.w3.org/checklink/ and found that most of the invalid links on that page pointed to parts of Jan Skibinski's former site (numeric-quest). Several of Jan's articles and programs have been quite popular (nice mix of quantum mechanics and practical tools, all with running commentary, not to mention his "Haskell Companion" project), so that subject has come up a few time on the mailing list. If we'd expect John and Olaf to monitor the dozens of Haskell-related mailing lists for haskell.org-related issues, and then to do "something" about them, they'd soon throw the towel - they aren't full-time admins. I admit to having made this naive assumption myself a few times.. So, this time round I instead downloaded the source of the webpage using wget, fixed up the numeric-quest links to go to the relevant parts of the Internet Archive (which is one of the places that saved the contents of Jan's site before that went down), added a few comments, and emailed the updated source to John and Olaf. This way, they only had to check the diff and the new links to see whether they were happy with the changes, and put the updated webpage online. All that happened within a day.. The difference is between something they can do in between their real jobs and something that will have to wait for "later", whenever that may be. Not the best system, but it works. Now, there are more links waiting for updates, even on that page, and especially the old stuff Hampus mentioned (ghc 2?-) needs some human looking into it. You don't have to fix everything at once to make a difference, but every one of you can make the site a little bit more consistent whenever you visit it - just as with Haskell implementations, libraries, and tools, bug reports are welcome, bug fixes even more so! Those of us who don't understand the innards of GHC&co. can still help in other ways, e.g., with the webpages. Over to you!-) Cheers, Claus From ajb@spamcop.net Thu Jun 12 05:08:08 2003 From: ajb@spamcop.net (Andrew J Bromage) Date: Thu, 12 Jun 2003 14:08:08 +1000 Subject: Non-determinism, backtracking and Monads In-Reply-To: <3EE7062E.5000605@info.unicaen.fr> References: <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <5.1.0.14.2.20030604214132.033fc090@127.0.0.1> <5.1.0.14.2.20030608090933.024397a8@127.0.0.1> <3EE7062E.5000605@info.unicaen.fr> Message-ID: <20030612040808.GA16444@smtp.alicorna.com> G'day all. On Wed, Jun 11, 2003 at 12:36:30PM +0200, Jerzy Karczmarczuk wrote: > It is possible, instead of implementing the *data backtracking* through lazy > lists, to make lazy "backtrackable" continuations, permitting to redirect > the flow of control to produce something else. The two ways are - perhaps not > entirely equivalent, but essentially two orchestrations of the same > theme. > I lost my references, perhaps somebody?... If you're referring to the paper(s) by Ralf Hinze, they are most certainly equivalent. WARNING: Long post follows. Consider the simplified term implementation of a nondeterminism monad, which basically operates on lists: data Nondet1 a = Cons a (Nondet1 a) | Fail -- This is the "observer" method runNondet1 :: (Monad m) => Nondet1 a -> m a runNondet1 m = case m of Cons x _ -> return x Fail -> fail "no solutions" return a = Cons a Fail m >>= k = case m of Cons a n -> mplus (k a) (n >>= k) Fail -> Fail mzero = Fail mplus m n = case m of Cons a m' -> Cons a (mplus m' n) Fail -> n You can derive a continuation-passing implementation by transforming away the data structures. This is a technique well-known to practitioners of traditional lambda calculus. We'll start by abstracting the data structures out. We need replacements for both constructor functions (i.e. Cons and Fail) and the pattern matching used above. data Nondet1 a = Fail | Cons a (Nondet1 a) cons1 :: a -> Nondet1 a -> Nondet1 a cons1 a m = Cons a m fail1 :: Nondet1 a fail1 = Fail unpack1 :: Nondet1 a -> (a -> Nondet1 a -> b) -> b -> b unpack1 (Cons a m) c f = c a m unpack1 Fail c f = f The monad can now be re-implemented in terms of these operations: runNondet1 :: (Monad m) => Nondet1 a -> m a runNondet1 m = unpack1 m (\x _ -> return x) (fail "no solutions") return a = cons1 a fail1 m >>= k = unpack1 m (\a n -> k a `mplus` n >>= k) fail1 mzero = fail1 mplus m n = unpack1 m (\a m' -> cons1 a (mplus m' n)) n Note that there are now no data structures in here, only calls to fail1, cons1 and unpack1. We can implement these how we like so long as these properties hold: unpack1 fail1 c f = f unpack1 (cons1 x xs) c f = c x xs The lambda calculus solution is to make unpack1 the identity function. Unfortunately that doesn't entirely work in Haskell because of the type system, but we can get pretty close by using rank-2 types and a newtype constructor: -- Compare this with the type of unpack1 above newtype Nondet2 a = Nondet2 (forall b. (a -> Nondet2 a -> b) -> b -> b) fail2 :: Nondet2 a fail2 = Nondet2 (\c f -> f) cons2 :: a -> Nondet2 a -> Nondet2 a cons2 a m = Nondet2 (\c f -> c a m) unpack2 :: Nondet2 a -> (a -> Nondet2 a -> b) -> b -> b unpack2 (Nondet2 m) = m We can inline these functions everywhere to get: runNondet2 :: (Monad m) => Nondet2 a -> m a runNondet2 (Nondet2 m) = m (\x _ -> return x) (fail "no solutions") return a = Nondet2 (\c _ -> c a (Nondet2 (\_ f -> f))) (Nondet2 m) >>= k = m (\a n -> mplus (k a) (n >>= k)) (Nondet2 (\_ f -> f)) mzero = Nondet2 (\_ f -> f) mplus (Nondet2 m) n = m (\a m' -> Nondet2 (\c _ -> c a (mplus m' n))) n ...and we have a continuation-passing implementation. Note that this is not 100% identical to the one from Ralf's paper and tech report. Transforming the above code into Ralf's is left as an exercise. (It's tricky but mechanical.) Cheers, Andrew Bromage From m.p.donadio@ieee.org Fri Jun 13 03:37:25 2003 From: m.p.donadio@ieee.org (Matthew Donadio) Date: Thu, 12 Jun 2003 22:37:25 -0400 Subject: Green Card and Exceptions Message-ID: <3EE938E5.B385991B@ieee.org> Hi all, I have a couple of questions about Green Card and exceptions. I am interfaceing to the GSL to get access to a few functions, and eventually interface all of the special functions to Haskell. And unlike my DSP library, and am trying to get it right the first time. :) Below is a Green Card interface to one of the functions. %fun airy_Ai_e :: Double -> (Double, Double) %call (double x) %code int rc; % double val; % double err; % gsl_sf_result result; % rc = gsl_sf_airy_Ai_e(x, GSL_PREC_DOUBLE, &result); % val = result.val; % err = result.err; %result (double val, double err) This definition works, but it ignores the return code from the library function. The various return codes are from an enum defined in a header file. I would like to throw a Haskell exception (one of the ArithExceptions defined in Control.Exception) depending on the value of "rc". Do I need to create a new DIS for the return values (which are an enum defined in a header), change the function to return a triplet (var,err,rc), and then throw the exception in Haskell land? Is there a way I can do this directly from the GC interface? If I have to create a DIS, can this be shared across several modules that all need the same functionality? Thanks. -- Matthew Donadio (m.p.donadio@ieee.org) From alastair@reid-consulting-uk.ltd.uk Fri Jun 13 10:44:12 2003 From: alastair@reid-consulting-uk.ltd.uk (Alastair Reid) Date: Fri, 13 Jun 2003 10:44:12 +0100 Subject: Green Card and Exceptions In-Reply-To: <3EE938E5.B385991B@ieee.org> References: <3EE938E5.B385991B@ieee.org> Message-ID: <200306131044.12474.alastair@reid-consulting-uk.ltd.uk> On Friday 13 June 2003 3:37 am, Matthew Donadio wrote: > Hi all, > > I have a couple of questions about Green Card and exceptions. > > [...] > > This definition works, but it ignores the return code from the library > function. The various return codes are from an enum defined in a header > file. I would like to throw a Haskell exception (one of the > ArithExceptions defined in Control.Exception) depending on the value of > "rc". The %fail statements (described in the last few paragraphs of http://www.haskell.org/greencard/downloads/greencard-latest/type-sig.html) consist of two C expressions. For example: %fail {f == NULL} {errstring(errno)} The first is a test for failure. The second is an expression which returns a C string. If the test expression fails, the string expression is evaluated and used to generate a UserError. > If I have to create a > DIS, can this be shared across several modules that all need the same > functionality? It would be nice to be able to write something like: %fail POSIX_FD(fd) where POSIX_FD is something you defined elsewhere (e.g., it might test if its file-descriptor argument is -1). GreenCard can't do this. It would also be nice to be able to generate a different error instead of UserError. We'd need to specify the type and the exception constructor so a plausible syntax would be: %fail {f == NULL} (UserError (string {errstring(errno)})) [Detail: should it be a Haskell98 IOError constructor or a non-standard but widely implemented exception constructor? Should it be a function or a constuctor?] Again, GreenCard can't do that. As GreenCard maintainer, I've got to ask: - How many users of GreenCard are still out there? - Are you developing new libraries or just maintaining the ones you've got? - Is there a demand for new features? -- Alastair Reid From ijones@syntaxpolice.org Fri Jun 13 16:04:22 2003 From: ijones@syntaxpolice.org (Isaac Jones) Date: Fri, 13 Jun 2003 11:04:22 -0400 Subject: chance to help out on the wiki Message-ID: <877k7q3top.fsf@syntaxpolice.org> Greetings. We added a page "Fundamental Concepts" to the wiki so that we might have a very specific reference to pass along to people with questions, and to add links to definitions throughout the wiki. http://www.haskell.org/hawiki/FundamentalConcepts A lot of concepts need to be filled in, and if you haven't participated in the Wiki yet, now is a good time :) If you've never used a wiki, you can read about it here: http://www.haskell.org/hawiki/HelpForBeginners You might model your explanations after a page I wrote for PatternMatching which has: - a reference to a tutorial - a reference to the haskell report - an explanation - some examples Feel free to extend and / or correct anything already there. The front page of the wiki is here: http://www.haskell.org/hawiki/FrontPage peace, isaac From m.p.donadio@ieee.org Fri Jun 13 17:36:06 2003 From: m.p.donadio@ieee.org (Matthew Donadio) Date: Fri, 13 Jun 2003 12:36:06 -0400 Subject: Green Card and Exceptions References: <3EE938E5.B385991B@ieee.org> <200306131044.12474.alastair@reid-consulting-uk.ltd.uk> Message-ID: <3EE9FD76.3C708FBA@ieee.org> Alastair Reid wrote: > The %fail statements (described in the last few paragraphs of > http://www.haskell.org/greencard/downloads/greencard-latest/type-sig.html) > consist of two C expressions. For example: > > %fail {f == NULL} {errstring(errno)} > > The first is a test for failure. > The second is an expression which returns a C string. > > If the test expression fails, the string expression is evaluated and used to > generate a UserError. OK, I think I misread the manual. Sect 7.6 talks about functions with side effects, so I assumed that the function had to have type (IO a) to use %fail. > It would also be nice to be able to generate a different error instead of > UserError. We'd need to specify the type and the exception constructor so a > plausible syntax would be: > > %fail {f == NULL} (UserError (string {errstring(errno)})) > > [Detail: should it be a Haskell98 IOError constructor or a non-standard but > widely implemented exception constructor? Should it be a function or a > constuctor?] In the case of what I am doing, I'm not sure if IOError really make sense philosophically. The failures I need are underflow, overflow, loss of precision, etc. Since IOError is a type synonym for IOException, then perhaps accepting an Exception constructor is appropriate. To keep compatibility with old libraries it may be wise to keep %fail as is, and have a new directive %throw that accepts an Exception constructor, and uses either throw or throwIO. On the other hand, now that I know that I can use %fail with pure functions, I can make that work. > As GreenCard maintainer, I've got to ask: > - How many users of GreenCard are still out there? New GreenCard user. In my case, I need access to C land for typedefs and macros. I could write my own stubs, but GreenCard saves me this step. > - Are you developing new libraries or just maintaining the ones you've got? New library. > - Is there a demand for new features? A more generic %fail mechanism? Thanks for the response. -- Matthew Donadio (m.p.donadio@ieee.org) From gk@ninebynine.org Fri Jun 13 19:03:07 2003 From: gk@ninebynine.org (Graham Klyne) Date: Fri, 13 Jun 2003 19:03:07 +0100 Subject: List comprehensions In-Reply-To: <20030604195001.00007769.ddarius@hotpop.com> References: <20030604140844.GB11206@boris.qub.ac.uk> <5.1.0.14.2.20030604120335.00b9d798@127.0.0.1> <20030604140844.GB11206@boris.qub.ac.uk> Message-ID: <5.1.0.14.2.20030613181018.00bbd200@127.0.0.1> In a response to me on the "powerset" thread, you wrote: At 19:50 04/06/03 -0400, Derek Elkins wrote: >In fact, you could rewrite the >whole thing as concatMap (flip combinations as) [1..length as]. A list >comprehension with only one source and no filters is the same as a map. Is there any particular reason to avoid using a list comprehension, even if a map would do? I ask because I seem not infrequently to find that a list comprehension is more compact and easier to read, even though map could suffice. This may be when the applied function is relatively complex, and would otherwise require a sequence of 'where' definitions. My current example is this: [[ -- |Graph substitution function. -- This function performs the substitutions in 'vars', and -- replaces any nodes corresponding to unbound query variables -- with new blank nodes. rdfQuerySubsBlank :: RDFQueryBindings -> RDFGraph -> [RDFGraph] rdfQuerySubsBlank vars gr = [ remapLabels vs bs True g | v <- vars , let (g,vs) = rdfQuerySubs2 v gr , let bs = allLabels isBlank g ] ]] I could write it with map, but the ways I came up with all seemed convoluted and difficult to follow. #g ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From djsavimbi@phantomemail.com Fri Jun 13 10:50:02 2003 From: djsavimbi@phantomemail.com (David Savimbi) Date: Fri, 13 Jun 2003 10:50:02 +0100 Subject: please help Message-ID: <20030613215806.EDCC4422246@www.haskell.org> From=3A David Jonas Savimbi Johannesburg=2C South Africa Email=3A djsavimbi=40phantomemail=2Ecom june 13th=2C 2003=2E Dear Sir=2C It is my humble pleasure to write you this letter irrespective of the fact that you do not know me=2E However=2C I got your name through your country business directory here in my search for a reliable and trustworthy person that can assist me confidently=2E My name is Mr=2EJohn Jonas Savimbi=2E I am the son of Late Dr=2E Jonas Savimbi from Angola=2E I am 29 years old and I have got two younger sisters of same blood=2E Our mother died almost a year ago=2E We are all fighting for political asylum in South Africa=2E We cannot find a home in Angola anymore because of the war that our late father fought with the government of Angola until he died in that war=2E The government of Angola is now mad at us because our late father also wanted to be president and caused the people to fight the war for him because he was the president of UNITA political movement of Angola=2E So now we are in South Africa and we are suffering too much because we don't have money and the government of South Africa will not give jobs to asylum seekers=2E I am much concerned about my younger sisters who are finding it very difficult to manage in the situation=2E But I know that we should not suffer this way=2E I know that I must not let my younger sisters get into trouble because of money=2E So after consideration I am hereby begging for your assistance to help me to recover the sum of USD $29 Million which is my inheritance from my late mother=2E My late mother had taken this money with her to Spain in a diplomatic metal box marked =28Precious Stones=29=2E Subsequently she lodged the metal box =28As precious Stones=29 with a Securities and Valuables Protection company in Spain=2E I am supposed to be the beneficiary in the event of her death=2E However=2C all effort I made to go Spain to claim was refused by the Spainish embassy=2E And this was while it was still possible for me to travel=2E Now I cannot travel anywhere anymore=2E So in the situation that we are facing now=2C I must find somebody who can go to the Spain on my behalf=2E I understand that I will have to transfer my beneficiary rights unto you=2E I am willing to do so in the hope that you are a God fearing person who will not abandon us after you have the money=2E So from the bottom of my heart I am giving you 20% of the all the money=2E Once we have enough to sustain us sufficiently=2C you may be come our fund manager and invest the rest wisely for us=2E If you will be kind to assist us=2C please inform me urgently=2E Kind regards to you and your family=2E Sincerely=2C David Jonas savimbi From m.p.donadio@ieee.org Sat Jun 14 01:06:37 2003 From: m.p.donadio@ieee.org (Matthew Donadio) Date: Fri, 13 Jun 2003 20:06:37 -0400 Subject: Testing was Re: main modules in GHC, deriving differences between GHC and Hugs References: Message-ID: <3EEA670D.585E6E7A@ieee.org> (redirected to haskell-cafe) Hal Daume III wrote: > Yes, but there's a problem with this solution. Namely, if Foo.hs takes a > long time to compile, then you can't leverage having already created Foo.o > and Foo.hi when making the Main. Yeah, it's not perfect, but I think we just have different methodologies for testing. Typically, I do most of my development with ghci or hugs. Each module will have a single variable that represents the tests tests :: [Bool] tests = [ test1, test2, test3 ... ] and then I define a variable called test :: Bool test = and tests so I can just load a module and either evaluate tests or test to check things out. This generalizes to importing and testing several modules at once (as long as I take care of name conflists). This only works for simple modules, though. For more complicated ones, I have a "pretty" tester. For example, my Haskell FFT library is collection of mutually recursive modules. I have a specialzed test function for this that tests a range of lengths. It looks someone like main = testfft n1 n2 testfft n1 n2 = sequence $ map test1fft [n1..n2] test1fft n = do putStr $ show n ++ ":\t" putStr $ if ok then "OK\n" else "ERROR\n" where ok = and [ test1 n, test2 n, test3 n ] This way I can compile the code, and run the executable as ffttest 2 2048 | grep ERROR and I am confident that I get full coverage of the algorithm. I am always to hear about other methods of automated testing. -- Matthew Donadio (m.p.donadio@ieee.org) From accinv-22028747-33746300hb53hf1j100d39EKACEGHG@domeus.co.uk Sat Jun 14 02:14:04 2003 From: accinv-22028747-33746300hb53hf1j100d39EKACEGHG@domeus.co.uk (Team domeus) Date: Sat, 14 Jun 2003 03:14:04 +0200 (CEST) Subject: REPLY REQUIRED: Confirm subscription to group Intelligent Learning Message-ID: --00----------------------0000----------------------00 Content-Type: multipart/alternative; boundary="11----------------------1111----------------------11" --11----------------------1111----------------------11 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 7bit Hello haskell-cafe@haskell.org, thanks for your interest in the group Intelligent Learning (intelligentlearning@domeus.co.uk). If you would like to accept this invitation, please return this eMail by clicking on reply or subscribe via the Web. http://uk.domeus.com/public/subscribe.jsp?tsp=1055553244893&gid=337463&uid=22028747&sig=FKEGIPGNMHBLDAEH&action=subscribeToSingleGroup If you are not interested in joining, please ignore this eMail and you will receive no further eMails from us. The group owner sends the following welcome message: ----------------------------- Welcome to Intelligent Learning! Our systems and programs can help you to successfully optimize your professional potential in a changing world. To be able to progress efficiently in any area today, we promote new smart working and learning systems through new techniques, tools and methodologies (TTMs) in key Smart Learning Areas: Knowledge Management, Change Management, Quantitative Learning, Qualitative Learning, Skill Management and Business Intelligence. For more information visit our web www.amjsmartlearning.com info@amjsmartlearning.com ----------------------------- If you would like to use the full range of features, just log in at http://uk.domeus.com using the following log-in information: username: haskell-cafe@haskell.org password: fetifak8 If your eMail address has been added to this list without your consent and you do not wish to receive eMails from Domeus, please forward this message to: set_account_inactive@domeus.co.uk. Please note that this will disable your eMail address throughout the Domeus system. Best regards, Your Domeus Team --11----------------------1111----------------------11 Content-Type: text/html; charset=iso-8859-1 Content-Transfer-Encoding: 7bit domeus
 
system message   
Hello haskell-cafe@haskell.org,

thanks for your interest in the group Intelligent Learning (intelligentlearning@domeus.co.uk)

If you would like to accept this invitation, please return this eMail by clicking on reply or subscribe via the Web.

Subscribe

If you are not interested in joining, please ignore this eMail and you will receive no further eMails from us.

The group owner sends the following welcome message:
-----------------------------

Welcome to Intelligent Learning! Our systems and programs can help you to successfully optimize your professional potential in a changing world. To be able to progress efficiently in any area today, we promote new smart working and learning systems through new techniques, tools and methodologies (TTMs) in key Smart Learning Areas: Knowledge Management, Change Management, Quantitative Learning, Qualitative Learning, Skill Management and Business Intelligence. For more information visit our web www.amjsmartlearning.com info@amjsmartlearning.com

-----------------------------

If you would like to use the full range of features, just log in at http://uk.domeus.com using the following log-in information:

username: haskell-cafe@haskell.org
password: fetifak8

If your eMail address has been added to this list without your consent and you do not wish to receive eMails from Domeus, please forward this message to: set_account_inactive@domeus.co.uk.

Best regards,
Your Domeus Team

 
--11----------------------1111----------------------11-- --00----------------------0000----------------------00 Content-Type: image/gif; name="logo.gif" Content-Transfer-Encoding: base64 Content-ID: R0lGODlh8ABEAMQAAP////3y0vzssPnehfbMOCQmJ+Hh4P7659jVyePFWuDUqZSPfMOxd9bFi1dU S3JuZMLAu/eTHKempQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAA AAAALAAAAADwAEQAAAX/ICCOZGmeaKqubOu+cCzPdK0SeK7vBDD8wKBw4Bsaf8XjMKkMAgTQqHQq eFKvUBQWawp4v+BwICUuf1uHtHrNPth48ByziaQL53R807qd8vtRWoBSXWZlZIZiaG2MaW9xcHpK kkeURpZLg4SagSecWSWJiiiiYYuNbY+QO5h3dk6vQK1On1W1gpyFpV6Iu2MsqIyqq3KxdcazssZE t7een7q7vdLAwWzDxD3Lycex3MzQzibiI768pOan1o412Trf8NvbzdDPuaHp6L7q69jE8cjkIaN3 b1w9EuZ+nUjIz5q/VQC9CfRGUBMui/j26aO2Yt2ah5AivhJp588gk4Au/57MyDFaqYbBQMYhmWfi yIorDRYsl29hTxUe1ciMZLNk0Tw4U9rDiPAny5fVgg7lQXPP0T1J+6hU2lSjT69Ag7pp5w5H1UlX J2XdslXrU1HToHYUO5VVkAYMFjxw4ODBgwUNuo1MW2ktl6U5eYJ9mwgmKhsyDEgoQLmyZcoPEEDe zLmz58+gN5fFYeDB5dOXHTCQGHAgNIYiYHdtqZh2aMijF6DeffnB4NYUX/eUXVvubOO3cbszzdtB Aee8A1sFflO4V+KxnWZfnJzsqgTQe0tA4OiAAQjMT0uvZKwBggbw4SO1zhE7APv3tXefQQw8agcS jGXCAZOph1YsBUygoP+CBcyXi2z24YfffjEQk95uAaJwwIWUHfhKggtO0CBW9MkVoX4TUvjCKgzw ZpkDBqRQYGW+XWIMiAuOqFaJcG1nm4T6qbhiHAm4mFqMKMxI2WpL3BiiiA5aBKF2QHIn5JBwcOhA BFxGcNkED6igm2U2IvikjoXx2JiPyOVnZYpXrkBkal12eRoEKRwQXgHrKWNmiGhecsuU3FVpW5wt xDFmZXXW2ZsKELzY5A946eWXXwswiSODRzSwgKWXhvoXYIR4gYAEqKZqKqh/jRfGqaB+Op5LAQgw QAK45prAAAoIIKCbAZyaKqoCgEECBBIgm6xmJkj2qaiYogoBkiDtWUD/o3ZeRu0JeyrgCgMOPHlm i2cO0UC44qbLYK9VeLHAmRCgm+4DBnjxgLoKPvArGANg628ECVQB7L1PImCsCAeI60AJBsiLb4gO MEsDHEW++O+dKijJpCwMPPxwoANs6nGIveb37pkeFxCABCMX0FUC/8ZMBBgEh2jwGQiLG+YIB4g8 soLbVshDi5ddfJkEKhhgWY1A9PxzuoE6/LSCDrQbwMlTU+3zvDwJEPPXYWC9oAIHi6AwCSxnveDO /PGwaGVbNmptAQusEJ4DQqStNqdANLA3ySb/nTWSXsD89b8J0CzuzecAkPCTbANQM9QP/wpDlv/V OXcBSKtwoRCT5/jc/+hbo9kx1M9Bp27nAOgt+Mide4FtwGEIYHidihdcNgBnjyD1BBIY4IYbBiAA 4vGW28BharvBuMK7lZUgcgHMDu84AuK6PILrDJKHsAiliVu3CNyLOK0jkqXrwLSOH4BA6GCWM3sZ DWAroNhAn/B4iJH/DuCwyOLLX6YVtMvxYHmWEZGILoOn51kmAToQGd6OEDo04W8CEDjC6fhnhQtK gAp6Ele9wmAAhX3Ba4eLWe5CRC02KGwNF2zZAgIQkxscsDfQulRfFlDAE1xoByJj2hAqGIQLGkCD OuuguNhFiOmVQQAm9EK/UvivYtlLhDxTQwB0tgbs/a0ANUwBHN62sP/O3G0HUhMi6MoFBCMiEXJK fBITAyE1lYnBeE9ywBcUQMUqfsGIWVTDC4Xyu6cFqBFyGtoCn9PDyCwNiJBTAhHbuLg3chAKF5xj Fpx4xygGYIp9bNQKF9RCNXiRfx9p2N/0hUgb7qBilWmghiAAgeSVQEkLgCTElFDHIopLApZcUN0w uUQqAKCOZvAkCus0gLIdgApg8GAgQ5jHj4gAAXp5zl62yRefOeAxrgTii2zpOOh803MPRKP44sNO +FkwXZliJ158toBnCiCTxuTkqzwZAGw1wJnYsuLK4AkBBBhUAoVkZRpQ08MSngmcYhxjb5KHgD2x zgTGg9sBX2e6103/gAFxJJkxkXlHCYLhdl1KALtqpQCUcgkMCnjdN9XgM87R8qYSgN9MhRFOHcAS buMpXk6/dNESXCiXO4AAR4XgUXDg0w/6BMMpF6THL4AylC8FQyF/ptANva6r1+ipDjbnIuedQEkF iMRWWyaEGHLVqcX0A0nFwM9+YpVLzZSq4HZqntfVspURpZiRTiOxEkTKMgyIRAO2dqbpDXFvEwzp 2PJ5pjJMlWpicOnhEicGpXoMfl1t3d/qCVEUrOJtLqIXCg6rUaIMAFz4eoCn2CgEcv2sABuTrII0 WYW5gkEACcJRVcNwqxTSzgzY3Nr6lKbAfFnzfYw90wP+WtoTEIOs/zQqKglQWwAIurZveGGAePt0 xMD0yQgNgIB418te+dACCgqIr3yvAAADCMC+9mXcqwzAX/OM0AxTEMMBdsFfBBS0XmoocL36KxSe FfimEEYAf2nYD7HyYDfTbSQA4nWaxM6EMGUKzoOcQhzsiIWcGqKLhV/5nwV4jwSn2pyHP0wdo7hm xIspsVNODAMer/iV2BVgN3czYxqz5sjVwTFtdLwYH7vAyaYtCwIH+xzvQgTEkxKxlEj8ExOr+Mlf 3kxFqWyZQyLqzGhOs4pG0wMC+MdIALJyNs6SplwMajg9gbKa21YWAOQgAXnhi3MEmKk2j4bOggqH mgxRnB61Typ79vOOO/x8aDYjOhOKVrKJ8hzmSAutz5a2NJbvYBj6EoojevY0liYd6kOP+r12XrQZ Gr2mR3tE1XxmdaVdXeMoneTO1+E0pHFtQFDvus+vlkWpjXlquaSa2Ik0trQnnWwkLNsPzXb0s6Ed WF1Pe87VBkesNe1o2Wyb29Y9trep3WsSjXvLwfbKudFdglZ/+x/hRolWgF0fYd+a3iyw97rB3e4d vfsk2a71vAEuAoHPWdQFr7NF+L1peXea4SZw+D8gjuSSXLtUeLb4sDGe7ntDhOO/0fKvZX0INmn7 4iQfgcZPzuuO+zolFC+3vysc8577/Oc/DwEAOw== --00----------------------0000----------------------00 Content-Type: image/gif; name="corner.gif" Content-Transfer-Encoding: base64 Content-ID: R0lGODdhpQBHAPcAAP766/733vzrsv734vvqqvXFGv778Pncd/jXY////wAAAAAAAAAAAAAAAAAA AAAAAGQBAAAFAAAAWJVYAGoEBQCk+BIAbDXnd9gHVQBkAQAAAAAAALT4EgBQE+d3WJVYAAUAAAAA AAAA5gEbAAEAAABg+RIA6rhAAGoEBQAFAAAAAAAAAOYBGwDmc+d3YCBVAAAAAAB04P1/vUvndxgA AAAeh/d3GAAAAAAAAAAAAAAAAAAAABz5EgAoAAkAAAAAAAAAAAA8+RIAAAATABny+XcHAAAAEAcT AAAAEwAAAAAAFPkSAAAAAACw/xIA1Cz6d2DY+nf/////APoSALFM93dIBRMAaPoSAAAAAABw+hIA QwAAAAIAAABaAFwA+D0TAFoACAII0BYAAAAAAAAAAABg2PoQQPoSAHZI93exTPd3SAUTAID6EgDo +xIAAAAAAEYAAAAAAAAAUPoSAAAAAACeAgAAAQAAAIhMFQDA7VoAAAQAAFD6EgDquEAAiEwVAAIA AAAABAAADPoSALxB6HfA7VoAbcP3d9B1+3duw/d3eH0TAFjSFgAAAAAArfL5dwAAEwBQ0hYAAAAA ADT6EgAAABMAGfL5dyQAAACADBMAAAATAKBDEwAM+hIA8U73dzT7EgDULPp3YNj6d//////4+hIA VEf3d4AMEwBsd+d3CAAAAKhzSAAAAAAAWNIWAGx353cAAAAAAQAAAAAALgBwMBMAWgBcAAEAAAAt AC4AAAAAAFT6EgAAAAIAsP8SAES583coyvN3/////9Qs+nfcTUMAWNIWAGx353cAAAAAIAAAAAAX w3un38EBADBXukjfwQEAN4bC+dvBAQAAAAALAgAAAAAAAIz7EgBjb3JuZXIuZ2lmAABsd+d3AAAA AAAAAAC6KOd3IAEAABQAAAASCwHkRPsSAKoo8HcAABMACAAEABgBAABsd+d3AAAAAAAAAAAAAAAA AAAAAMTARADKQxMA7E4VAM5DEwDWc0gA/////6BDEwAuwUQAykMTACH5BAAAAAAALAAAAAClAEcA QAj/ABMIHEiwoMGDCBMqXMiwocOHECM2LECxosWLBRIc2Mixo8cDAwWIHEmypACBAVKqXMkSIYCX MGPKlEizps2bOHPq3MmzIYKfQIMKRZCAgNGjSJMSSDCgqdOnUAckMEC1qtWrBnpq3cq1q9evYBd+ HMsxrNmzaNOqXauWLFm2cOPKnUtXLca7FTW6/RjSpF+RKFkKVulSpmGYdXPixat3b8e+f00GHiy4 8GHDiXEO3Qy0qNLPRplGHd10KtbTVDPP5czZM2iloklHNY0aq2q5jj3e3r0292PewM36Lhu8uNfh G40rX868ecLFdxv7hhyZ5GTKKy1fjun8OfSL0nNT/68OOAH2yge3Y+5+8Dt45CAFki95/XwA7eoB sG/vPi/88eTVdx5+6u1nEGubufYaUrHJ9hRttVll4FYIDqXggqE5OFuEtk3YU4VCXYhhgxpKxeFV Hn4IYmcYJkWihhCemCJP/81o40A13mhjjjqmyGOPE/4I5H5CDtldkUY2h2SSTDbp5JPL9ecfcgBW JyB2BG5no5QUhedYlZFdSVmWl23JpZd7gfmXmIOReZiZUqLplpp+sYmeQflxNyOXGeU4n3Xm2UdY enm+BGd/cr4l35/lCToonoXqt+eZfjJ6UqCOurleinwmOhadkmEqqKYzzbgiiy0e9aKDMXIIpU+n Eo+VqqolPniihK8uFKussy5Vq1OtRpirrrGKuOCqsgVb27AK7Wrsa8iSpixqzCbkbK++/mriralV e9C1vUY72rSnefttsdiKuyG3WZlb0JLuzgVvvHHNSy9b9t7bFpX6ZpZvv2f9C3BYAg/8VcEGd4Vw wlstzHBPDj+8U8QS50RxxTddjHFNGm/s8ccgh+xhQAA7 --00----------------------0000----------------------00-- From christian@snowblack.de Fri Jun 13 18:39:53 2003 From: christian@snowblack.de (Christian Buschmann) Date: Fri, 13 Jun 2003 19:39:53 +0200 Subject: gtk2hs Message-ID: <3EEA0C69.20504@gmx.net> Hi! I tried to implement a simple counter with gtk2hs. To increase my counter I defined following event: onClicked btn $ do si <- textBufferGetStartIter tb ei <- textBufferGetEndIter tb val <- textBufferGetText tb si ei False textBufferSetText tb $ show $ (+1) $ read val But now I don't want always read the textfield to get my counter-value, I would like to save the state of my increased value and would like to pass it to the next call of the function. How can I do this? thanks Christian This is the complete code: import Gtk quitDialog :: IO Bool quitDialog = ..... main :: IO () main = do initGUI --main window win <- windowNew onDelete win (\_->(quitDialog>>= (return . not ))) onDestroy win mainQuit vb <- vBoxNew True 5 hb <- hBoxNew True 5 btn <- buttonNewFromStock stockExecute btn2 <- buttonNewFromStock stockQuit tv <- textViewNew tb <- textBufferNew Nothing textBufferSetText tb "0" textViewSetEditable tv False textViewSetCursorVisible tv False textViewSetBuffer tv tb boxPackStartDefaults vb tv boxPackStartDefaults vb hb boxPackStartDefaults hb btn boxPackStartDefaults hb btn2 hgf <- onClicked btn $ do si <- textBufferGetStartIter tb ei <- textBufferGetEndIter tb val <- textBufferGetText tb si ei False textBufferSetText tb $ show $ (+1) $ read val disconnect hgf onClicked btn2 $ do quit <- quitDialog if quit then widgetDestroy win else return () containerAdd win vb widgetShowAll win mainGUI From ashley@semantic.org Sun Jun 15 04:51:48 2003 From: ashley@semantic.org (Ashley Yakeley) Date: Sat, 14 Jun 2003 20:51:48 -0700 Subject: Haskell.org out of date References: <20030610201957.GA16028@persephone.dtek.chalmers.se> Message-ID: In article <20030610201957.GA16028@persephone.dtek.chalmers.se>, Hampus Ram wrote: > If it is the "community" we're obviously not doing it right, lots of > broken links and some that is there but does not work (e.g. the wish-list). I'm vaguely thinking of setting up a Haskell wish-list project on SourceForge. The idea is, people would contribute test-code for a given wish they have, and the test would succeed for any compiler that implemented the wish. -- Ashley Yakeley, Seattle WA From intelligentlearning-unsubscribe@domeus.co.uk Sun Jun 15 12:21:15 2003 From: intelligentlearning-unsubscribe@domeus.co.uk (Team domeus) Date: Sun, 15 Jun 2003 13:21:15 +0200 (CEST) Subject: Welcome to the group Intelligent Learning Message-ID: --00----------------------0000----------------------00 Content-Type: multipart/alternative; boundary="11----------------------1111----------------------11" --11----------------------1111----------------------11 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 7bit Hello haskell-cafe@haskell.org, You have been added to the group Intelligent Learning (intelligentlearning@domeus.co.uk). The group owner sends the following welcome message: ---------------------------- Welcome to Intelligent Learning! Our systems and programs can help you to successfully optimize your professional potential in a changing world. To be able to progress efficiently in any area today, we promote new smart working and learning systems through new techniques, tools and methodologies (TTMs) in key Smart Learning Areas: Knowledge Management, Change Management, Quantitative Learning, Qualitative Learning, Skill Management and Business Intelligence. For more information visit our web www.amjsmartlearning.com info@amjsmartlearning.com ---------------------------- If you do not wish to receive mails from this group, please return this eMail by clicking on reply. Alternatively, you can send an eMail to intelligentlearning-unsubscribe@domeus.co.uk. To unsubscribe via the web please use the following link: http://uk.domeus.com/public/unsubscribe.jsp?tsp=1055676075383&gid=337463&uid=22028747&sig=IMNEFGNIPDDOHMCM Either way you will be directly deleted from the distribution list. If you have any questions or concerns, please contact the moderators of this Domeus group at intelligentlearning-moderators@domeus.co.uk. If your eMail address has been added to this list without your consent and you do not wish to receive any eMails from Domeus, please forward this message to: set_account_inactive@domeus.co.uk. Please note that this will disable your eMail address throughout the Domeus system. If you have any questions or problems concerning domeus please contact admin@domeus.co.uk. Best regards, Your Domeus Team --11----------------------1111----------------------11 Content-Type: text/html; charset=iso-8859-1 Content-Transfer-Encoding: 7bit domeus
 
system message   
Hello haskell-cafe@haskell.org,

You have been added to the group Intelligent Learning (intelligentlearning@domeus.co.uk).

The group owner sends the following welcome message:
----------------------------

Welcome to Intelligent Learning! Our systems and programs can help you to successfully optimize your professional potential in a changing world. To be able to progress efficiently in any area today, we promote new smart working and learning systems through new techniques, tools and methodologies (TTMs) in key Smart Learning Areas: Knowledge Management, Change Management, Quantitative Learning, Qualitative Learning, Skill Management and Business Intelligence. For more information visit our web www.amjsmartlearning.com info@amjsmartlearning.com

----------------------------

If you do not wish to receive mails from this group, please return this eMail by clicking on reply. Alternatively, you can send an eMail to intelligentlearning-unsubscribe@domeus.co.uk.

To unsubscribe via the web please use the following link:
Unsubscribe

Either way you will be directly deleted from the distribution list.
If you have any questions or concerns, please contact the moderators of this Domeus group at intelligentlearning-moderators@domeus.co.uk.

If your eMail address has been added to this list without your consent and you do not wish to receive any eMails from Domeus, please forward this message to: set_account_inactive@domeus.co.uk.

Please note that this will disable your eMail address throughout the Domeus system. If you have any questions or problems concerning domeus please contact admin@domeus.co.uk.

Best regards,
Your Domeus Team

 
--11----------------------1111----------------------11-- --00----------------------0000----------------------00 Content-Type: image/gif; name="logo.gif" Content-Transfer-Encoding: base64 Content-ID: R0lGODlh8ABEAMQAAP////3y0vzssPnehfbMOCQmJ+Hh4P7659jVyePFWuDUqZSPfMOxd9bFi1dU S3JuZMLAu/eTHKempQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAA AAAALAAAAADwAEQAAAX/ICCOZGmeaKqubOu+cCzPdK0SeK7vBDD8wKBw4Bsaf8XjMKkMAgTQqHQq eFKvUBQWawp4v+BwICUuf1uHtHrNPth48ByziaQL53R807qd8vtRWoBSXWZlZIZiaG2MaW9xcHpK kkeURpZLg4SagSecWSWJiiiiYYuNbY+QO5h3dk6vQK1On1W1gpyFpV6Iu2MsqIyqq3KxdcazssZE t7een7q7vdLAwWzDxD3Lycex3MzQzibiI768pOan1o412Trf8NvbzdDPuaHp6L7q69jE8cjkIaN3 b1w9EuZ+nUjIz5q/VQC9CfRGUBMui/j26aO2Yt2ah5AivhJp588gk4Au/57MyDFaqYbBQMYhmWfi yIorDRYsl29hTxUe1ciMZLNk0Tw4U9rDiPAny5fVgg7lQXPP0T1J+6hU2lSjT69Ag7pp5w5H1UlX J2XdslXrU1HToHYUO5VVkAYMFjxw4ODBgwUNuo1MW2ktl6U5eYJ9mwgmKhsyDEgoQLmyZcoPEEDe zLmz58+gN5fFYeDB5dOXHTCQGHAgNIYiYHdtqZh2aMijF6DeffnB4NYUX/eUXVvubOO3cbszzdtB Aee8A1sFflO4V+KxnWZfnJzsqgTQe0tA4OiAAQjMT0uvZKwBggbw4SO1zhE7APv3tXefQQw8agcS jGXCAZOph1YsBUygoP+CBcyXi2z24YfffjEQk95uAaJwwIWUHfhKggtO0CBW9MkVoX4TUvjCKgzw ZpkDBqRQYGW+XWIMiAuOqFaJcG1nm4T6qbhiHAm4mFqMKMxI2WpL3BiiiA5aBKF2QHIn5JBwcOhA BFxGcNkED6igm2U2IvikjoXx2JiPyOVnZYpXrkBkal12eRoEKRwQXgHrKWNmiGhecsuU3FVpW5wt xDFmZXXW2ZsKELzY5A946eWXXwswiSODRzSwgKWXhvoXYIR4gYAEqKZqKqh/jRfGqaB+Op5LAQgw QAK45prAAAoIIKCbAZyaKqoCgEECBBIgm6xmJkj2qaiYogoBkiDtWUD/o3ZeRu0JeyrgCgMOPHlm i2cO0UC44qbLYK9VeLHAmRCgm+4DBnjxgLoKPvArGANg628ECVQB7L1PImCsCAeI60AJBsiLb4gO MEsDHEW++O+dKijJpCwMPPxwoANs6nGIveb37pkeFxCABCMX0FUC/8ZMBBgEh2jwGQiLG+YIB4g8 soLbVshDi5ddfJkEKhhgWY1A9PxzuoE6/LSCDrQbwMlTU+3zvDwJEPPXYWC9oAIHi6AwCSxnveDO /PGwaGVbNmptAQusEJ4DQqStNqdANLA3ySb/nTWSXsD89b8J0CzuzecAkPCTbANQM9QP/wpDlv/V OXcBSKtwoRCT5/jc/+hbo9kx1M9Bp27nAOgt+Mide4FtwGEIYHidihdcNgBnjyD1BBIY4IYbBiAA 4vGW28BharvBuMK7lZUgcgHMDu84AuK6PILrDJKHsAiliVu3CNyLOK0jkqXrwLSOH4BA6GCWM3sZ DWAroNhAn/B4iJH/DuCwyOLLX6YVtMvxYHmWEZGILoOn51kmAToQGd6OEDo04W8CEDjC6fhnhQtK gAp6Ele9wmAAhX3Ba4eLWe5CRC02KGwNF2zZAgIQkxscsDfQulRfFlDAE1xoByJj2hAqGIQLGkCD OuuguNhFiOmVQQAm9EK/UvivYtlLhDxTQwB0tgbs/a0ANUwBHN62sP/O3G0HUhMi6MoFBCMiEXJK fBITAyE1lYnBeE9ywBcUQMUqfsGIWVTDC4Xyu6cFqBFyGtoCn9PDyCwNiJBTAhHbuLg3chAKF5xj Fpx4xygGYIp9bNQKF9RCNXiRfx9p2N/0hUgb7qBilWmghiAAgeSVQEkLgCTElFDHIopLApZcUN0w uUQqAKCOZvAkCus0gLIdgApg8GAgQ5jHj4gAAXp5zl62yRefOeAxrgTii2zpOOh803MPRKP44sNO +FkwXZliJ158toBnCiCTxuTkqzwZAGw1wJnYsuLK4AkBBBhUAoVkZRpQ08MSngmcYhxjb5KHgD2x zgTGg9sBX2e6103/gAFxJJkxkXlHCYLhdl1KALtqpQCUcgkMCnjdN9XgM87R8qYSgN9MhRFOHcAS buMpXk6/dNESXCiXO4AAR4XgUXDg0w/6BMMpF6THL4AylC8FQyF/ptANva6r1+ipDjbnIuedQEkF iMRWWyaEGHLVqcX0A0nFwM9+YpVLzZSq4HZqntfVspURpZiRTiOxEkTKMgyIRAO2dqbpDXFvEwzp 2PJ5pjJMlWpicOnhEicGpXoMfl1t3d/qCVEUrOJtLqIXCg6rUaIMAFz4eoCn2CgEcv2sABuTrII0 WYW5gkEACcJRVcNwqxTSzgzY3Nr6lKbAfFnzfYw90wP+WtoTEIOs/zQqKglQWwAIurZveGGAePt0 xMD0yQgNgIB418te+dACCgqIr3yvAAADCMC+9mXcqwzAX/OM0AxTEMMBdsFfBBS0XmoocL36KxSe FfimEEYAf2nYD7HyYDfTbSQA4nWaxM6EMGUKzoOcQhzsiIWcGqKLhV/5nwV4jwSn2pyHP0wdo7hm xIspsVNODAMer/iV2BVgN3czYxqz5sjVwTFtdLwYH7vAyaYtCwIH+xzvQgTEkxKxlEj8ExOr+Mlf 3kxFqWyZQyLqzGhOs4pG0wMC+MdIALJyNs6SplwMajg9gbKa21YWAOQgAXnhi3MEmKk2j4bOggqH mgxRnB61Typ79vOOO/x8aDYjOhOKVrKJ8hzmSAutz5a2NJbvYBj6EoojevY0liYd6kOP+r12XrQZ Gr2mR3tE1XxmdaVdXeMoneTO1+E0pHFtQFDvus+vlkWpjXlquaSa2Ik0trQnnWwkLNsPzXb0s6Ed WF1Pe87VBkesNe1o2Wyb29Y9trep3WsSjXvLwfbKudFdglZ/+x/hRolWgF0fYd+a3iyw97rB3e4d vfsk2a71vAEuAoHPWdQFr7NF+L1peXea4SZw+D8gjuSSXLtUeLb4sDGe7ntDhOO/0fKvZX0INmn7 4iQfgcZPzuuO+zolFC+3vysc8577/Oc/DwEAOw== --00----------------------0000----------------------00 Content-Type: image/gif; name="corner.gif" Content-Transfer-Encoding: base64 Content-ID: R0lGODdhpQBHAPcAAP766/733vzrsv734vvqqvXFGv778Pncd/jXY////wAAAAAAAAAAAAAAAAAA AAAAAGQBAAAFAAAAWJVYAGoEBQCk+BIAbDXnd9gHVQBkAQAAAAAAALT4EgBQE+d3WJVYAAUAAAAA AAAA5gEbAAEAAABg+RIA6rhAAGoEBQAFAAAAAAAAAOYBGwDmc+d3YCBVAAAAAAB04P1/vUvndxgA AAAeh/d3GAAAAAAAAAAAAAAAAAAAABz5EgAoAAkAAAAAAAAAAAA8+RIAAAATABny+XcHAAAAEAcT AAAAEwAAAAAAFPkSAAAAAACw/xIA1Cz6d2DY+nf/////APoSALFM93dIBRMAaPoSAAAAAABw+hIA QwAAAAIAAABaAFwA+D0TAFoACAII0BYAAAAAAAAAAABg2PoQQPoSAHZI93exTPd3SAUTAID6EgDo +xIAAAAAAEYAAAAAAAAAUPoSAAAAAACeAgAAAQAAAIhMFQDA7VoAAAQAAFD6EgDquEAAiEwVAAIA AAAABAAADPoSALxB6HfA7VoAbcP3d9B1+3duw/d3eH0TAFjSFgAAAAAArfL5dwAAEwBQ0hYAAAAA ADT6EgAAABMAGfL5dyQAAACADBMAAAATAKBDEwAM+hIA8U73dzT7EgDULPp3YNj6d//////4+hIA VEf3d4AMEwBsd+d3CAAAAKhzSAAAAAAAWNIWAGx353cAAAAAAQAAAAAALgBwMBMAWgBcAAEAAAAt AC4AAAAAAFT6EgAAAAIAsP8SAES583coyvN3/////9Qs+nfcTUMAWNIWAGx353cAAAAAIAAAAAAX w3un38EBADBXukjfwQEAN4bC+dvBAQAAAAALAgAAAAAAAIz7EgBjb3JuZXIuZ2lmAABsd+d3AAAA AAAAAAC6KOd3IAEAABQAAAASCwHkRPsSAKoo8HcAABMACAAEABgBAABsd+d3AAAAAAAAAAAAAAAA AAAAAMTARADKQxMA7E4VAM5DEwDWc0gA/////6BDEwAuwUQAykMTACH5BAAAAAAALAAAAAClAEcA QAj/ABMIHEiwoMGDCBMqXMiwocOHECM2LECxosWLBRIc2Mixo8cDAwWIHEmypACBAVKqXMkSIYCX MGPKlEizps2bOHPq3MmzIYKfQIMKRZCAgNGjSJMSSDCgqdOnUAckMEC1qtWrBnpq3cq1q9evYBd+ HMsxrNmzaNOqXauWLFm2cOPKnUtXLca7FTW6/RjSpF+RKFkKVulSpmGYdXPixat3b8e+f00GHiy4 8GHDiXEO3Qy0qNLPRplGHd10KtbTVDPP5czZM2iloklHNY0aq2q5jj3e3r0292PewM36Lhu8uNfh G40rX868ecLFdxv7hhyZ5GTKKy1fjun8OfSL0nNT/68OOAH2yge3Y+5+8Dt45CAFki95/XwA7eoB sG/vPi/88eTVdx5+6u1nEGubufYaUrHJ9hRttVll4FYIDqXggqE5OFuEtk3YU4VCXYhhgxpKxeFV Hn4IYmcYJkWihhCemCJP/81o40A13mhjjjqmyGOPE/4I5H5CDtldkUY2h2SSTDbp5JPL9ecfcgBW JyB2BG5no5QUhedYlZFdSVmWl23JpZd7gfmXmIOReZiZUqLplpp+sYmeQflxNyOXGeU4n3Xm2UdY enm+BGd/cr4l35/lCToonoXqt+eZfjJ6UqCOurleinwmOhadkmEqqKYzzbgiiy0e9aKDMXIIpU+n Eo+VqqolPniihK8uFKussy5Vq1OtRpirrrGKuOCqsgVb27AK7Wrsa8iSpixqzCbkbK++/mriralV e9C1vUY72rSnefttsdiKuyG3WZlb0JLuzgVvvHHNSy9b9t7bFpX6ZpZvv2f9C3BYAg/8VcEGd4Vw wlstzHBPDj+8U8QS50RxxTddjHFNGm/s8ccgh+xhQAA7 --00----------------------0000----------------------00-- From Team domeus Sun Jun 15 12:26:30 2003 From: Team domeus (Team domeus) Date: Sun, 15 Jun 2003 13:26:30 +0200 (CEST) Subject: no subject Message-ID: --00----------------------0000----------------------00 Content-Type: multipart/alternative; boundary="11----------------------1111----------------------11" --11----------------------1111----------------------11 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 7bit Hello haskell-cafe@haskell.org, You successfully unsubscribed from the group intelligentlearning@domeus.co.uk. You will not receive any more messages from this group. Best regards, Your Domeus Team --11----------------------1111----------------------11 Content-Type: text/html; charset=iso-8859-1 Content-Transfer-Encoding: 7bit domeus
 
system message   
Hello haskell-cafe@haskell.org,

You successfully unsubscribed from the group intelligentlearning@domeus.co.uk. You will not receive any more messages from this group.

Best regards,
Your Domeus Team

 
--11----------------------1111----------------------11-- --00----------------------0000----------------------00 Content-Type: image/gif; name="logo.gif" Content-Transfer-Encoding: base64 Content-ID: R0lGODlh8ABEAMQAAP////3y0vzssPnehfbMOCQmJ+Hh4P7659jVyePFWuDUqZSPfMOxd9bFi1dU S3JuZMLAu/eTHKempQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAA AAAALAAAAADwAEQAAAX/ICCOZGmeaKqubOu+cCzPdK0SeK7vBDD8wKBw4Bsaf8XjMKkMAgTQqHQq eFKvUBQWawp4v+BwICUuf1uHtHrNPth48ByziaQL53R807qd8vtRWoBSXWZlZIZiaG2MaW9xcHpK kkeURpZLg4SagSecWSWJiiiiYYuNbY+QO5h3dk6vQK1On1W1gpyFpV6Iu2MsqIyqq3KxdcazssZE t7een7q7vdLAwWzDxD3Lycex3MzQzibiI768pOan1o412Trf8NvbzdDPuaHp6L7q69jE8cjkIaN3 b1w9EuZ+nUjIz5q/VQC9CfRGUBMui/j26aO2Yt2ah5AivhJp588gk4Au/57MyDFaqYbBQMYhmWfi yIorDRYsl29hTxUe1ciMZLNk0Tw4U9rDiPAny5fVgg7lQXPP0T1J+6hU2lSjT69Ag7pp5w5H1UlX J2XdslXrU1HToHYUO5VVkAYMFjxw4ODBgwUNuo1MW2ktl6U5eYJ9mwgmKhsyDEgoQLmyZcoPEEDe zLmz58+gN5fFYeDB5dOXHTCQGHAgNIYiYHdtqZh2aMijF6DeffnB4NYUX/eUXVvubOO3cbszzdtB Aee8A1sFflO4V+KxnWZfnJzsqgTQe0tA4OiAAQjMT0uvZKwBggbw4SO1zhE7APv3tXefQQw8agcS jGXCAZOph1YsBUygoP+CBcyXi2z24YfffjEQk95uAaJwwIWUHfhKggtO0CBW9MkVoX4TUvjCKgzw ZpkDBqRQYGW+XWIMiAuOqFaJcG1nm4T6qbhiHAm4mFqMKMxI2WpL3BiiiA5aBKF2QHIn5JBwcOhA BFxGcNkED6igm2U2IvikjoXx2JiPyOVnZYpXrkBkal12eRoEKRwQXgHrKWNmiGhecsuU3FVpW5wt xDFmZXXW2ZsKELzY5A946eWXXwswiSODRzSwgKWXhvoXYIR4gYAEqKZqKqh/jRfGqaB+Op5LAQgw QAK45prAAAoIIKCbAZyaKqoCgEECBBIgm6xmJkj2qaiYogoBkiDtWUD/o3ZeRu0JeyrgCgMOPHlm i2cO0UC44qbLYK9VeLHAmRCgm+4DBnjxgLoKPvArGANg628ECVQB7L1PImCsCAeI60AJBsiLb4gO MEsDHEW++O+dKijJpCwMPPxwoANs6nGIveb37pkeFxCABCMX0FUC/8ZMBBgEh2jwGQiLG+YIB4g8 soLbVshDi5ddfJkEKhhgWY1A9PxzuoE6/LSCDrQbwMlTU+3zvDwJEPPXYWC9oAIHi6AwCSxnveDO /PGwaGVbNmptAQusEJ4DQqStNqdANLA3ySb/nTWSXsD89b8J0CzuzecAkPCTbANQM9QP/wpDlv/V OXcBSKtwoRCT5/jc/+hbo9kx1M9Bp27nAOgt+Mide4FtwGEIYHidihdcNgBnjyD1BBIY4IYbBiAA 4vGW28BharvBuMK7lZUgcgHMDu84AuK6PILrDJKHsAiliVu3CNyLOK0jkqXrwLSOH4BA6GCWM3sZ DWAroNhAn/B4iJH/DuCwyOLLX6YVtMvxYHmWEZGILoOn51kmAToQGd6OEDo04W8CEDjC6fhnhQtK gAp6Ele9wmAAhX3Ba4eLWe5CRC02KGwNF2zZAgIQkxscsDfQulRfFlDAE1xoByJj2hAqGIQLGkCD OuuguNhFiOmVQQAm9EK/UvivYtlLhDxTQwB0tgbs/a0ANUwBHN62sP/O3G0HUhMi6MoFBCMiEXJK fBITAyE1lYnBeE9ywBcUQMUqfsGIWVTDC4Xyu6cFqBFyGtoCn9PDyCwNiJBTAhHbuLg3chAKF5xj Fpx4xygGYIp9bNQKF9RCNXiRfx9p2N/0hUgb7qBilWmghiAAgeSVQEkLgCTElFDHIopLApZcUN0w uUQqAKCOZvAkCus0gLIdgApg8GAgQ5jHj4gAAXp5zl62yRefOeAxrgTii2zpOOh803MPRKP44sNO +FkwXZliJ158toBnCiCTxuTkqzwZAGw1wJnYsuLK4AkBBBhUAoVkZRpQ08MSngmcYhxjb5KHgD2x zgTGg9sBX2e6103/gAFxJJkxkXlHCYLhdl1KALtqpQCUcgkMCnjdN9XgM87R8qYSgN9MhRFOHcAS buMpXk6/dNESXCiXO4AAR4XgUXDg0w/6BMMpF6THL4AylC8FQyF/ptANva6r1+ipDjbnIuedQEkF iMRWWyaEGHLVqcX0A0nFwM9+YpVLzZSq4HZqntfVspURpZiRTiOxEkTKMgyIRAO2dqbpDXFvEwzp 2PJ5pjJMlWpicOnhEicGpXoMfl1t3d/qCVEUrOJtLqIXCg6rUaIMAFz4eoCn2CgEcv2sABuTrII0 WYW5gkEACcJRVcNwqxTSzgzY3Nr6lKbAfFnzfYw90wP+WtoTEIOs/zQqKglQWwAIurZveGGAePt0 xMD0yQgNgIB418te+dACCgqIr3yvAAADCMC+9mXcqwzAX/OM0AxTEMMBdsFfBBS0XmoocL36KxSe FfimEEYAf2nYD7HyYDfTbSQA4nWaxM6EMGUKzoOcQhzsiIWcGqKLhV/5nwV4jwSn2pyHP0wdo7hm xIspsVNODAMer/iV2BVgN3czYxqz5sjVwTFtdLwYH7vAyaYtCwIH+xzvQgTEkxKxlEj8ExOr+Mlf 3kxFqWyZQyLqzGhOs4pG0wMC+MdIALJyNs6SplwMajg9gbKa21YWAOQgAXnhi3MEmKk2j4bOggqH mgxRnB61Typ79vOOO/x8aDYjOhOKVrKJ8hzmSAutz5a2NJbvYBj6EoojevY0liYd6kOP+r12XrQZ Gr2mR3tE1XxmdaVdXeMoneTO1+E0pHFtQFDvus+vlkWpjXlquaSa2Ik0trQnnWwkLNsPzXb0s6Ed WF1Pe87VBkesNe1o2Wyb29Y9trep3WsSjXvLwfbKudFdglZ/+x/hRolWgF0fYd+a3iyw97rB3e4d vfsk2a71vAEuAoHPWdQFr7NF+L1peXea4SZw+D8gjuSSXLtUeLb4sDGe7ntDhOO/0fKvZX0INmn7 4iQfgcZPzuuO+zolFC+3vysc8577/Oc/DwEAOw== --00----------------------0000----------------------00 Content-Type: image/gif; name="corner.gif" Content-Transfer-Encoding: base64 Content-ID: R0lGODdhpQBHAPcAAP766/733vzrsv734vvqqvXFGv778Pncd/jXY////wAAAAAAAAAAAAAAAAAA AAAAAGQBAAAFAAAAWJVYAGoEBQCk+BIAbDXnd9gHVQBkAQAAAAAAALT4EgBQE+d3WJVYAAUAAAAA AAAA5gEbAAEAAABg+RIA6rhAAGoEBQAFAAAAAAAAAOYBGwDmc+d3YCBVAAAAAAB04P1/vUvndxgA AAAeh/d3GAAAAAAAAAAAAAAAAAAAABz5EgAoAAkAAAAAAAAAAAA8+RIAAAATABny+XcHAAAAEAcT AAAAEwAAAAAAFPkSAAAAAACw/xIA1Cz6d2DY+nf/////APoSALFM93dIBRMAaPoSAAAAAABw+hIA QwAAAAIAAABaAFwA+D0TAFoACAII0BYAAAAAAAAAAABg2PoQQPoSAHZI93exTPd3SAUTAID6EgDo +xIAAAAAAEYAAAAAAAAAUPoSAAAAAACeAgAAAQAAAIhMFQDA7VoAAAQAAFD6EgDquEAAiEwVAAIA AAAABAAADPoSALxB6HfA7VoAbcP3d9B1+3duw/d3eH0TAFjSFgAAAAAArfL5dwAAEwBQ0hYAAAAA ADT6EgAAABMAGfL5dyQAAACADBMAAAATAKBDEwAM+hIA8U73dzT7EgDULPp3YNj6d//////4+hIA VEf3d4AMEwBsd+d3CAAAAKhzSAAAAAAAWNIWAGx353cAAAAAAQAAAAAALgBwMBMAWgBcAAEAAAAt AC4AAAAAAFT6EgAAAAIAsP8SAES583coyvN3/////9Qs+nfcTUMAWNIWAGx353cAAAAAIAAAAAAX w3un38EBADBXukjfwQEAN4bC+dvBAQAAAAALAgAAAAAAAIz7EgBjb3JuZXIuZ2lmAABsd+d3AAAA AAAAAAC6KOd3IAEAABQAAAASCwHkRPsSAKoo8HcAABMACAAEABgBAABsd+d3AAAAAAAAAAAAAAAA AAAAAMTARADKQxMA7E4VAM5DEwDWc0gA/////6BDEwAuwUQAykMTACH5BAAAAAAALAAAAAClAEcA QAj/ABMIHEiwoMGDCBMqXMiwocOHECM2LECxosWLBRIc2Mixo8cDAwWIHEmypACBAVKqXMkSIYCX MGPKlEizps2bOHPq3MmzIYKfQIMKRZCAgNGjSJMSSDCgqdOnUAckMEC1qtWrBnpq3cq1q9evYBd+ HMsxrNmzaNOqXauWLFm2cOPKnUtXLca7FTW6/RjSpF+RKFkKVulSpmGYdXPixat3b8e+f00GHiy4 8GHDiXEO3Qy0qNLPRplGHd10KtbTVDPP5czZM2iloklHNY0aq2q5jj3e3r0292PewM36Lhu8uNfh G40rX868ecLFdxv7hhyZ5GTKKy1fjun8OfSL0nNT/68OOAH2yge3Y+5+8Dt45CAFki95/XwA7eoB sG/vPi/88eTVdx5+6u1nEGubufYaUrHJ9hRttVll4FYIDqXggqE5OFuEtk3YU4VCXYhhgxpKxeFV Hn4IYmcYJkWihhCemCJP/81o40A13mhjjjqmyGOPE/4I5H5CDtldkUY2h2SSTDbp5JPL9ecfcgBW JyB2BG5no5QUhedYlZFdSVmWl23JpZd7gfmXmIOReZiZUqLplpp+sYmeQflxNyOXGeU4n3Xm2UdY enm+BGd/cr4l35/lCToonoXqt+eZfjJ6UqCOurleinwmOhadkmEqqKYzzbgiiy0e9aKDMXIIpU+n Eo+VqqolPniihK8uFKussy5Vq1OtRpirrrGKuOCqsgVb27AK7Wrsa8iSpixqzCbkbK++/mriralV e9C1vUY72rSnefttsdiKuyG3WZlb0JLuzgVvvHHNSy9b9t7bFpX6ZpZvv2f9C3BYAg/8VcEGd4Vw wlstzHBPDj+8U8QS50RxxTddjHFNGm/s8ccgh+xhQAA7 --00----------------------0000----------------------00-- From duncan@coutts.uklinux.net Sun Jun 15 23:07:12 2003 From: duncan@coutts.uklinux.net (Duncan Coutts) Date: Sun, 15 Jun 2003 23:07:12 +0100 Subject: gtk2hs In-Reply-To: <3EEA0C69.20504@gmx.net> References: <3EEA0C69.20504@gmx.net> Message-ID: <20030615230712.586beb99.duncan@coutts.uklinux.net> On Fri, 13 Jun 2003 19:39:53 +0200 Christian Buschmann wrote: > I tried to implement a simple counter with gtk2hs. To increase my > counter I defined following event: > > onClicked btn $ do si <- textBufferGetStartIter tb > ei <- textBufferGetEndIter tb > val <- textBufferGetText tb si ei False > textBufferSetText tb $ show $ (+1) $ read val > > But now I don't want always read the textfield to get my counter-value, > I would like to save the state of my increased value and would like to > pass it to the next call of the function. > How can I do this? Use an IORef or an MVar eg. (untested code) let initialCounterValue = 0 counter <- newIORef initialCounterValue btn `onClicked` do counterValue <- readIORef counter tb `textBufferSetText` show (counterValue + 1) writeIORef counter (counterValue + 1) or with an MVar: let initialCounterValue = 0 counter <- newMVar initialCounterValue btn `onClicked` do modifyMVar_ counter (\counter -> do tb `textBufferSetText` show (counterValue + 1) return (counterValue + 1)) The second version is threadsafe. There are more elegant techniques that hide the evil imperitive state (the IORef or MVar) but this is the easiest technique to start with. Duncan From tony2003@yahoo.ca Mon Jun 16 16:03:45 2003 From: tony2003@yahoo.ca (tony2003@yahoo.ca) Date: Mon, 16 Jun 03 15:03:45 ÖĐšúąęןʹźä Subject: Italian-crafted Rolex - only $65 - $140!! Free SHIPPING ! ! Message-ID: <20030616070540.ADD6F421EEB@www.haskell.org> ------=_NextPart_000_0029_52703B42.6EB5A3E Content-Type: text/html Content-Transfer-Encoding: base64 PEJPRFkgYmdDb2xvcj0jZmZmZmZmPg0KPERJVj48U1RST05HPjxGT05UIGNvbG9yPSNmZjAw MDAgZmFjZT1WZXJkYW5hPlBsZWFzZSBub3RlIHRvIHNlbmQgQUxMIFJFUExZIA0KZS1tYWls IGRpcmVjdCB0byBvdXIgU2FsZXMgUmVwcmVzZW50YXRpdmUgYXQ6IDwvRk9OVD48L1NUUk9O Rz48QSANCmhyZWY9Im1haWx0bzpRdWVzdGlvbnNAU3dpc3NXYXRjaFNhbGUuY29tIj48U1RS T05HPjxGT05UIA0KZmFjZT1WZXJkYW5hPlF1ZXN0aW9uc0BTd2lzc1dhdGNoU2FsZS5jb208 L0ZPTlQ+PC9TVFJPTkc+PC9BPjxGT05UIGNvbG9yPSMwMDAwZmYgDQpmYWNlPVZlcmRhbmE+ PFNUUk9ORz4gPC9TVFJPTkc+PC9GT05UPjwvRElWPg0KPERJVj4mbmJzcDs8L0RJVj4NCjxE SVY+PEZPTlQgZmFjZT1WZXJkYW5hIHNpemU9Mj5IaSwmbmJzcDs8QlI+VGhhbmsgeW91IGZv ciBleHByZXNzaW5nIGludGVyZXN0IGluIA0KQVRHV1Mgd2F0Y2hlcy48L0ZPTlQ+PC9ESVY+ DQo8RElWPjxGT05UIGZhY2U9VmVyZGFuYSBzaXplPTI+V2Ugd291bGQgbGlrZSB0byB0YWtl IHRoaXMgb3Bwb3J0dW5pdHkgdG8gb2ZmZXIgDQp5b3Ugb3VyIGZpbmUgc2VsZWN0aW9uIG9m IEl0YWxpYW4gY3JhZnRlZCBSb2xleCBUaW1lcGllY2VzLiZuYnNwOzxCUj5Zb3UgY2FuIA0K dmlldyBvdXIgbGFyZ2Ugc2VsZWN0aW9uIG9mIFJvbGV4ZXMgKGluY2x1ZGluZyBCcmVpdGxp bmcsIFRhZyBIZXVlciwgQ2FydGllciANCmV0YykgYXQ6PC9GT05UPjwvRElWPg0KPERJVj4m bmJzcDs8L0RJVj4NCjxESVY+PEZPTlQgZmFjZT1WZXJkYW5hIHNpemU9Mj48QSANCmhyZWY9 Imh0dHA6Ly93d3cuU3dpc3NXYXRjaFNhbGUuY29tOjYzMjMvIj48U1RST05HPmh0dHA6Ly93 d3cuU3dpc3NXYXRjaFNhbGUuY29tOjYzMjMvPC9TVFJPTkc+PC9BPjwvRk9OVD48L0RJVj4N CjxESVY+Jm5ic3A7PC9ESVY+DQo8RElWPjxGT05UIGZhY2U9VmVyZGFuYSBzaXplPTI+Rm9y IGFsbCBvcmRlcnMgcGxhY2VkIGluIHRoZSBtb250aCBvZiBKdW5lLCBhbGwgDQpzaGlwcGlu ZyBhbmQgaGFuZGxpbmcgY2hhcmdlcyB3aWxsIGJlIGZyZWUuJm5ic3A7PEJSPkFzIHdlIGFy ZSB0aGUgZGlyZWN0IA0KbWFudWZhY3R1cmVycywgeW91IGFyZSBndWFyYW50ZWVkIG9mIGxv d2VzdCBwcmljZXMgYW5kIGhpZ2hlc3QgcXVhbGl0eSBlYWNoIGFuZCANCmV2ZXJ5IHRpbWUg eW91IHB1cmNoYXNlIGZyb20gdXMuJm5ic3A7PEJSPllvdSBtYXkgYWxzbyBiZSBpbnRlcmVz dGVkIHRvIGtub3cgDQp0aGF0IHdlIGhhdmUgdGhlIGZvbGxvd2luZyBicmFuZHMgYXZhaWxh YmxlIGluIG91ciB3aWRlIHNlbGVjdGlvbiBhcyB3ZWxsOiANCjwvRk9OVD48L0RJVj4NCjxE SVY+PEZPTlQgZmFjZT1WZXJkYW5hIHNpemU9Mj4xLiBMZWF0aGVyIGJhbmQgRGF5dG9uYSAo bGFkaWVzIGFuZCBtZW6hr3MpIDxCUj4yLiANCkJsYW5jcGFpbjxCUj4zLiBGb3J0aXM8QlI+ NC4gSmFlZ2VyIExlQ291dHJlPEJSPjUuIExvbmdpbmVzPEJSPjYuIE1vbnQgDQpCbGFuYzxC Uj43LiBNb3ZhZG88QlI+OC4gT3JpczxCUj45LiBSb2dlciBEdWJ1aXM8QlI+MTAuIFVseXNz ZTxCUj4xMS4gDQpaZW5pdGg8QlI+MTIuIEF1ZGVtYXIgUGlndWV0PEJSPjEzLiBCcmVpdGxp bmc8QlI+MTQuIEJ2Z2xhcmk8QlI+MTUuIA0KQ2FydGllcjxCUj4xNi4gQ29ydW08QlI+MTcu IER1bmhpbGw8QlI+MTguIEZyYW5jayBNdWxsZXI8QlI+MTkuIEdlcmFyZCANClBlcnJlZ2F1 eDxCUj4yMC4gSVdDPEJSPjIxLiBJV0M8QlI+MjIuIFBhbmVyYWk8QlI+MjMuIFBhdGVrIFBo aWxpcHBlPEJSPjI0LiBUYWcgDQpIZXVlcjxCUj4yNS4gVmFjaGVyb24gQ29uc3RhbnRpbjxC Uj4mbmJzcDs8QlI+SWYgeW91IHNlZSBhbnl0aGluZyB0aGF0IG1pZ2h0IA0KaW50ZXJlc3Qg eW91LCBvciBpZiB5b3UgaGF2ZSBhbnkgcXVlc3Rpb25zLCBwbGVhc2UgZG9uJ3QgaGVzaXRh dGUgdG8gdmlzaXQgb3VyIA0Kd2Vic2l0ZSBhdDo8L0ZPTlQ+PC9ESVY+DQo8RElWPiZuYnNw OzwvRElWPg0KPERJVj48Rk9OVCBmYWNlPVZlcmRhbmEgc2l6ZT0yPjxBIA0KaHJlZj0iaHR0 cDovL3d3dy5Td2lzc1dhdGNoU2FsZS5jb206NjMyMy8iPjxTVFJPTkc+aHR0cDovL3d3dy5T d2lzc1dhdGNoU2FsZS5jb206NjMyMy88L1NUUk9ORz48L0E+PC9GT05UPjwvRElWPg0KPERJ Vj4mbmJzcDs8L0RJVj4NCjxESVY+PEZPTlQgZmFjZT1WZXJkYW5hIHNpemU9Mj5JIGNlcnRh aW5seSBsb29rIGZvcndhcmQgdG8gaGVhcmluZyBmcm9tIA0KeW91LjwvRk9OVD48L0RJVj4N CjxESVY+PEZPTlQgZmFjZT1WZXJkYW5hIHNpemU9Mj5CZXN0IHJlZ2FyZHMsPC9GT05UPjwv RElWPg0KPERJVj48Rk9OVCBmYWNlPVZlcmRhbmEgc2l6ZT0yPkNhbDwvRk9OVD48L0RJVj4N CjxESVY+PEZPTlQgc2l6ZT0yPjxGT05UIGZhY2U9VmVyZGFuYT5EaXZpc2lvbiBTYWxlcyBN YW5hZ2VyPEJSPkFUR1dTJm5ic3A7Jm5ic3A7IA0KPEJSPllvdSByZWNlaXZlZCB0aGlzIGVt YWlsIGJlY2F1c2UgeW91ciBoYXZlIHByZXZpb3VzIHB1cmNoYXNlZCBmcm9tLCBvciANCmlu cXVpcmVkIGFib3V0IG91ciBwcm9kdWN0IGxpbmUgdW5kZXIgQVRHV1MuIElmIHlvdSBkbyBu b3Qgd2FudCB0byByZWNlaXZlIA0KZnVydGhlciBtYWlsaW5ncyBmcm9tIEFUR1dTLCB1bnN1 YnNjcmliZSBieSBzZW5kaW5nIGFuIGVtYWlsIHdpdGggdGhlIHRpdGxlIA0KaGVhZGluZzog REVMRVRFIGluIHRoZSBzdWJqZWN0IGxpbmUgdG8gPC9GT05UPjxBIA0KaHJlZj0ibWFpbHRv OnVuc3Vic2NyaWJlQFN3aXNzV2F0Y2hTYWxlLmNvbSI+PFNUUk9ORz48Rk9OVCANCmZhY2U9 VmVyZGFuYT51bnN1YnNjcmliZUBTd2lzc1dhdGNoU2FsZS5jb208L0ZPTlQ+PC9TVFJPTkc+ PC9BPjxGT05UIA0KZmFjZT1WZXJkYW5hPjxTVFJPTkc+IDwvU1RST05HPjwvRk9OVD48L0ZP TlQ+PC9ESVY+DQo8RElWPiZuYnNwOzwvRElWPg0KPERJVj48U1RST05HPjxGT05UIGNvbG9y PSNmZjAwMDAgZmFjZT1WZXJkYW5hPnBsZWFzZSBub3RlIHRvIHNlbmQgQUxMIFJFUExZIA0K ZS1tYWlsIGRpcmVjdCB0byBvdXIgU2FsZXMgUmVwcmVzZW50YXRpdmUgYXQ6PEJSPjwvRk9O VD48L1NUUk9ORz48QSANCmhyZWY9Im1haWx0bzpRdWVzdGlvbnNAU3dpc3NXYXRjaFNhbGUu Y29tIj48U1RST05HPjxGT05UIA0KZmFjZT1WZXJkYW5hPlF1ZXN0aW9uc0BTd2lzc1dhdGNo U2FsZS5jb208L0ZPTlQ+PC9TVFJPTkc+PC9BPjxGT05UIGNvbG9yPSMwMDAwZmYgDQpmYWNl PVZlcmRhbmE+PFNUUk9ORz4gPC9TVFJPTkc+PC9GT05UPjwvRElWPg0KPERJVj4mbmJzcDs8 L0RJVj4NCjxESVY+PEZPTlQgc2l6ZT0yPjwvRk9OVD4mbmJzcDs8L0RJVj48L0JPRFk+DQog ICAg ------=_NextPart_000_0029_52703B42.6EB5A3E-- From josemak22@caramail.com Mon Jun 16 23:03:44 2003 From: josemak22@caramail.com (Joseph Makale) Date: Mon, 16 Jun 2003 15:03:44 -0700 Subject: Please contact me Message-ID: <20030616220357.E02A4421F19@www.haskell.org> MR=2E JOSEPH MAKALE DEPARTMENT OF MINERALS AND ENERGY PRETORIA=2C SOUTH AFRICA=2E JUNE16TH=2E=2C 2003 Sir=2C It is my great pleasure to write you this letter on behalf of my colleagues=2E Your information was given to me by a member of the South African Export Promotion Council =28SAEPC=29 who was with the Government delegation on a trip to your country for a United Nations bilateral conference talk on sustainable development to encourage foreign investors=2E I have decided to seek a confidential co-operation with you in the execution of a deal here-under for the benefit of all parties and hope you will keep it confidential because of the nature of the business=2E Within the Department of Minerals and Energy where I work as an assistant Director of Audit=2C with the co-operation of two other top officials=2C we have in our possession an overdue contractor payment in US Dollars funds=2E The said funds represent certain percentage of the contract value executed on behalf of my Department by a foreign contracting firm=2C =28Pearls Ltd=29 which we the officials over-invoiced to the amount of US$15=2C200=2C000 =28Fifteen Million Two Hundred Thousand US Dollars=29=2E Since the present elected Government is determined to pay foreign contractors all debts owed=2C so as to maintain good relations with foreign governments and non-governmental agencies=2C we included our bills for approvals with the Department of Finance and the Reserve Bank of South Africa =28RBSA=29=2E We are 100+% sure of funds approvals to anyone or company we =28The Audit Committee=29 recommend as part of the sub-contractors who did jobs for the Department=2E We are seeking your assistance to front as the sub-contractor of the unclaimed funds=2C since we are not allowed to operate foreign accounts=2E Details and change of beneficiary information upon application for claim to reflect payment and approvals will be secured on behalf of You=2Fyour Company=2E My colleagues and I are prepared to give you US$2=2E5m while we take US$7=2E4m and the balance of US$5=2E3m for taxes and miscellaneous expenses incurred=2E This business is completely safe and secure=2C provided you treat it with utmost confidentiality=2E It does not matter whether You=2Fyour Company does contract projects=2C as a transfer of rights will be secured in favor of You=2Fyour Company through the Federal high Court of South Africa before we can proceed=2E I have reposed my confidence in you and hope that you will not disappoint us=2E Kindly notify me immediately for further details upon your acceptance of this proposal=2E You can contact me by email=2E Yours Faithfully=2C Joseph Makale =28Mr=2E=29 From ytcgj@sina.com Tue Jun 17 10:16:34 2003 From: ytcgj@sina.com (Software Promote Center) Date: Tue, 17 Jun 2003 17:16:34 +0800 Subject: Protect your privacy Message-ID: <20030617091623.572AA422275@www.haskell.org> Hi, Our product can protect your privacy. http://www.linren.com Your computer is spying on you now! It stores all the evidence into your hard disk. Anyone using your computer can see where you have been on Internet, what images and movies you have seen, and even anything you have done on your computer could be seen by others. The Windows built-in functions will not protect you, most of the tracks can not be erased with them. Privacy Cleaner Pro is designed to protect you by cleaning up all the unwanted history data on your computer. With simply one click, Privacy Cleaner Pro allows you to erase the cache, cookies,history,typed URLs,autocomplete memory from your browsers, and Window's temp folder,run history, search history, open/save history, recent documents,etc. With Privacy Cleaner Pro, you can easily erase the tracks of applications,such as playlist of Realplayer, Mediaplayer, QuickTime,recent files of Office, Acrobat ,Winzip,etc.Privacy Cleaner Pro can also let you customize what file(s) to be erased With Privacy Cleaner Pro's Securely Cleaning feature, you can erase the files completely, which can not be recovered by others. For more information go to: http://www.linren.com Best Regards, Software Promote Center From hdaume@ISI.EDU Tue Jun 17 15:50:23 2003 From: hdaume@ISI.EDU (Hal Daume III) Date: Tue, 17 Jun 2003 07:50:23 -0700 (PDT) Subject: Type classes and code generation In-Reply-To: Message-ID: (Moved to the Cafe) > Yes, exactly. Every class is translated to a data type declaration, > and every instance is translated to an element of that data type - a > dictionary. (Note that you can't actually write those declarations in > Haskell 98 in general, because they can have polymorphic fields; but > this is a simple extension to the language). Keith, could you elaborate on this parenthetical? Under what circumstances can you not create the dictionary datatype for a class in Haskell 98 (where the class itself is H98 :P)? - Hal From Keith.Wansbrough@cl.cam.ac.uk Tue Jun 17 16:05:18 2003 From: Keith.Wansbrough@cl.cam.ac.uk (Keith Wansbrough) Date: Tue, 17 Jun 2003 16:05:18 +0100 Subject: Type classes and code generation In-Reply-To: Your message of "Tue, 17 Jun 2003 07:50:23 PDT." Message-ID: > (Moved to the Cafe) > > > Yes, exactly. Every class is translated to a data type declaration, > > and every instance is translated to an element of that data type - a > > dictionary. (Note that you can't actually write those declarations in > > Haskell 98 in general, because they can have polymorphic fields; but > > this is a simple extension to the language). > > Keith, could you elaborate on this parenthetical? Under what > circumstances can you not create the dictionary datatype for a class in > Haskell 98 (where the class itself is H98 :P)? Sure: > class C a where > pair :: b -> (b,a) > > instance C () where > pair x = (x,()) > > instance C Int where > pair x = (x,42) > > main = do print (pair "hello" :: (String,())) > print (pair "world" :: (String,Int)) is perfectly fine Haskell 98. But > data C a = C { pair :: b -> (b,a) } > > dCUnit = C { pair = \ x -> (x,()) } > > dCInt = C { pair = \ x -> (x,42::Int) } > > main = do print (pair dCUnit "hello" :: (String,())) > print (pair dCInt "world" :: (String,Int)) doesn't work: classprob2.hs:1: Type variable not in scope: `b' classprob2.hs:1: Type variable not in scope: `b' You need to change the first line to this: > data C a = C { pair :: forall b. b -> (b,a) } and then it works fine (with -fglasgow-exts). But you've now stepped outside the bounds of Haskell 98. This is a contrived example, but Functor and Monad from the standard Prelude both have this property - they have universally-quantified variables in the types of some of their methods; not all their variables are constrained by the class constraint. HTH. --KW 8-) From Keith.Wansbrough@cl.cam.ac.uk Tue Jun 17 16:06:59 2003 From: Keith.Wansbrough@cl.cam.ac.uk (Keith Wansbrough) Date: Tue, 17 Jun 2003 16:06:59 +0100 Subject: Type classes and code generation In-Reply-To: Your message of "Tue, 17 Jun 2003 16:05:18 BST." Message-ID: > You need to change the first line to this: > > > data C a = C { pair :: forall b. b -> (b,a) } > > and then it works fine (with -fglasgow-exts). But you've now stepped > outside the bounds of Haskell 98. (oops, replying to myself... sure sign of madness! :) ) I hasten to add that this is *not* the same as existential quantification; note carefully the location of the forall wrt the constructor. --KW 8-) -- Keith Wansbrough http://www.cl.cam.ac.uk/users/kw217/ University of Cambridge Computer Laboratory. From yu-@div.club.ne.jp Thu Jun 19 01:18:18 2003 From: yu-@div.club.ne.jp (Koji Nakahara) Date: Thu, 19 Jun 2003 09:18:18 +0900 Subject: Help: Stack-overflow and tail-recursive functions Message-ID: <20030619091818.1d6e1947.yu-@div.club.ne.jp> Hi I've written a function that is tail-recursive and takes a list(queue) as one of its arguments. However the function fails because of "Stack space overflow"(GHC) or "ERROR - Garbage collection fails to reclaim sufficient space"(hugs). For example (simplified), both of these results in stack-overflow: f1 100000 [0,1,2], and even f2 100000 [0,1,2], where, f1 0 l = l f1 n l = f (n-1) $ take 3 $ l ++ [0,1] f2 0 l = l f2 n l = f2 (n - 1) $! (take 3 $ l ++ [0,1]) Why f2 overflows? How to avoid this stack-overflow? From t-hald@microsoft.com Thu Jun 19 01:36:28 2003 From: t-hald@microsoft.com (Hal Daume) Date: Wed, 18 Jun 2003 17:36:28 -0700 Subject: Help: Stack-overflow and tail-recursive functions Message-ID: <935F630FDD8A7F4CB1A0412C7CA4371405ED06B2@RED-MSG-10.redmond.corp.microsoft.com> Note that there is essentially no difference between f1 and f2. When you $! in f2, all it does is ensure that the argument isn't undefined. It doesn't evaluate any of the list. Try $!! from the DeepSeq module or write your own list-forcing function. For me, the following works: f1 0 l =3D l f1 n l =3D f1 (n-1) $!! (take 3 $ l ++ [0,1]) f $!! x =3D force x `seq` f x where force [] =3D () force (x:xs) =3D x `seq` force xs whereas it doesn't without the $!!. -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume > -----Original Message----- > From: haskell-cafe-admin@haskell.org=20 > [mailto:haskell-cafe-admin@haskell.org] On Behalf Of Koji Nakahara > Sent: Wednesday, June 18, 2003 5:18 PM > To: haskell-cafe@haskell.org > Subject: Help: Stack-overflow and tail-recursive functions >=20 >=20 > Hi >=20 > I've written a function that is tail-recursive and takes > a list(queue) as one of its arguments. > However the function fails because of > "Stack space overflow"(GHC) or "ERROR - Garbage collection=20 > fails to reclaim sufficient space"(hugs). >=20 > For example (simplified), both of these results in=20 > stack-overflow: f1 100000 [0,1,2], and even f2 100000 [0,1,2], >=20 > where, > f1 0 l =3D l > f1 n l =3D f (n-1) $ take 3 $ l ++ [0,1] >=20 > f2 0 l =3D l > f2 n l =3D f2 (n - 1) $! (take 3 $ l ++ [0,1]) >=20 > Why f2 overflows? >=20 > How to avoid this stack-overflow? >=20 > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org=20 > http://www.haskell.org/mailman/listinfo/haskel> l-cafe >=20 From yu-@div.club.ne.jp Thu Jun 19 03:41:25 2003 From: yu-@div.club.ne.jp (Koji Nakahara) Date: Thu, 19 Jun 2003 11:41:25 +0900 Subject: Help: Stack-overflow and tail-recursive functions In-Reply-To: <935F630FDD8A7F4CB1A0412C7CA4371405ED06B2@RED-MSG-10.redmond.corp.microsoft.com> References: <935F630FDD8A7F4CB1A0412C7CA4371405ED06B2@RED-MSG-10.redmond.corp.microsoft.com> Message-ID: <20030619114125.79026710.yu-@div.club.ne.jp> On Wed, 18 Jun 2003 17:36:28 -0700 "Hal Daume" wrote: > Note that there is essentially no difference between f1 and f2. When > you $! in f2, all it does is ensure that the argument isn't undefined. > It doesn't evaluate any of the list. Try $!! from the DeepSeq module or > write your own list-forcing function. Thank you very much. I understand. However my original program still (or maybe from the beginning) stack-overflows at another point, in the middle of the evaluation of "forpaintbdry". Please give me some advice. ----------- -- snippet of the program for painting a random matrix from its boundary. module Main where import System import Random import Array import Ix import List main = putStrLn $ show $ forpaintbdry $ rmat 200 forpaintbdry m = [(pos, Live) | pos <- (uncurry bdryidxlist) $ bounds m , isUnknown $ m ! pos ] bdryidxlist :: (Int, Int) -> (Int, Int) -> [(Int, Int)] bdryidxlist (a1, a2) (b1, b2) = nub $ [(ab, j) | ab <- [a1, b1], j <- [a2..b2]] ++ [(i, ab) | ab <- [a2, b2], i <- [a1..b1]] rmat n = listArray ((1,1),(n,n)) $ map ct (randoms (mkStdGen 1) ::[Bool]) where ct True = Unknown ct False = Dead data CellColor = Live | Unknown | Dead isUnknown Unknown = True isUnknown _ = False instance Show CellColor where show Live = "Live" show Unknown = "Unknown" show Dead = "Dead" From t-hald@microsoft.com Thu Jun 19 17:53:09 2003 From: t-hald@microsoft.com (Hal Daume) Date: Thu, 19 Jun 2003 09:53:09 -0700 Subject: Help: Stack-overflow and tail-recursive functions Message-ID: <935F630FDD8A7F4CB1A0412C7CA4371405ED06B7@RED-MSG-10.redmond.corp.microsoft.com> The problem here is actually in the rmat function, not the forpaintbdry or whatever. The problem is that, afaik, the listArray function doesn't deforest the list argument (someone can correct me here, though). That is, you write: rmat n =3D listArray ... [a big list] and then this list is first built, then the array is filled in. You can see that this is a problem by replacing your main with: main =3D print (m ! snd (bounds m)) where m =3D rmat 800 This will stack overflow too. Solution: use mutable arrays and fill them in by hand :). -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume > -----Original Message----- > From: Koji Nakahara [mailto:yu-@div.club.ne.jp]=20 > Sent: Wednesday, June 18, 2003 7:41 PM > To: Hal Daume; haskell-cafe@haskell.org > Subject: Re: Help: Stack-overflow and tail-recursive functions >=20 >=20 > On Wed, 18 Jun 2003 17:36:28 -0700 > "Hal Daume" wrote: >=20 > > Note that there is essentially no difference between f1 and=20 > f2. When > > you $! in f2, all it does is ensure that the argument isn't=20 > undefined. > > It doesn't evaluate any of the list. Try $!! from the=20 > DeepSeq module or > > write your own list-forcing function. >=20 > Thank you very much. I understand. >=20 > However my original program still (or maybe from the=20 > beginning) stack-overflows > at another point, in the middle of the evaluation of "forpaintbdry". >=20 > Please give me some advice. > ----------- > -- snippet of the program for painting a random matrix from=20 > its boundary.=20 > module Main where > import System > import Random > import Array > import Ix > import List >=20 > main =3D putStrLn $ show $ forpaintbdry $ rmat 200 >=20 > forpaintbdry m =3D [(pos, Live) | pos <- (uncurry bdryidxlist)=20 > $ bounds m , isUnknown $ m ! pos ] >=20 > bdryidxlist :: (Int, Int) -> (Int, Int) -> [(Int, Int)] > bdryidxlist (a1, a2) (b1, b2) =3D nub $ [(ab, j) | ab <- [a1,=20 > b1], j <- [a2..b2]] ++=20 > [(i, ab) | ab <- [a2, b2], i <-=20 > [a1..b1]] >=20 > rmat n =3D listArray ((1,1),(n,n)) $ map ct (randoms=20 > (mkStdGen 1) ::[Bool])=20 > where ct True =3D Unknown > ct False =3D Dead >=20 > data CellColor =3D Live | Unknown | Dead >=20 > isUnknown Unknown =3D True > isUnknown _ =3D False >=20 > instance Show CellColor where > show Live =3D "Live" > show Unknown =3D "Unknown" > show Dead =3D "Dead" >=20 >=20 From oleg@pobox.com Fri Jun 20 03:19:35 2003 From: oleg@pobox.com (oleg@pobox.com) Date: Thu, 19 Jun 2003 19:19:35 -0700 (PDT) Subject: Help: Stack-overflow and tail-recursive functions Message-ID: <200306200219.h5K2JZJ5046263@adric.fnmoc.navy.mil> It seems the problem is indeed in rmat: > rmat n = listArray ((1,1),(n,n)) $ map ct (randoms (mkStdGen 1) ::[Bool]) > where ct True = Unknown > ct False = Dead To be more precise, the problem is in randoms. If you replace rmat with the following rmat n = array ((1,1),(n,n)) $ zipWith (\ind v -> v `seq` (ind,v)) [(i,j) | i<-range, j<-range] $ map ct (randoms (mkStdGen 1) ::[Bool]) where ct True = Unknown ct False = Dead range = [1..n] then > main = putStrLn $ show $ forpaintbdry $ rmat 400 computes without problems (compiled with GHC 5.04.1, no flags). BTW, GHCi didn't have any problem even with the original code. From yu-@div.club.ne.jp Fri Jun 20 05:39:00 2003 From: yu-@div.club.ne.jp (Koji Nakahara) Date: Fri, 20 Jun 2003 13:39:00 +0900 Subject: listArray and stack overflow (Re: Help: Stack-overflow and tail-recursive functions) In-Reply-To: <20030619091818.1d6e1947.yu-@div.club.ne.jp> References: <20030619091818.1d6e1947.yu-@div.club.ne.jp> Message-ID: <20030620133900.219eaed1.yu-@div.club.ne.jp> I did some experiments and now suspect that the culprit is the infinite list. When I replace rmat with > rmat n = listArray ((1,1),(n,n)) [1..] -- no longer random , > print (m ! (300, 300)) where m = rmat 800 fails again. However, if I use a finite list as the second argument of listArray: > rmat n = listArray ((1,1),(n,n)) [1..(n*n)] , then the program runs without problems. This definition works as well as oleg's. >rmat n = listArray ((1,1),(n,n)) $!! (take (n*n) $ map ct (randoms (mkStdGen 1) ::[Bool]) ) > where ct True = Unknown > ct False = Dead I think: If the list is infinite, listArray doesn't return an array as data. Each time an element of the array is used, the list is evaluated. This lazy evaluation require some stack(and the access time cannot be constant?). Is it correct? Thank you. From t-hald@microsoft.com Fri Jun 20 15:54:50 2003 From: t-hald@microsoft.com (Hal Daume) Date: Fri, 20 Jun 2003 07:54:50 -0700 Subject: Help: Stack-overflow and tail-recursive functions Message-ID: <935F630FDD8A7F4CB1A0412C7CA4371405ED06C2@RED-MSG-10.redmond.corp.microsoft.com> > GHCi didn't have any problem even with the original code. mine didn't either, until I increased the "200" to around "1500"...it's probably OS/memory specific. From bkelly@sourcereview.net Sat Jun 21 02:23:42 2003 From: bkelly@sourcereview.net (Brett Kelly) Date: Fri, 20 Jun 2003 18:23:42 -0700 Subject: Using an accumulator, "iterating"... Message-ID: <20030621012342.GB1797@inkedmn.homelinux.org> --1UWUbFP1cBYEclgG Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Hello all, I'm trying to write a function that takes a list and a element (same type) = and returns the index of the first instance of the element in the list. like: getindex "brett" 'e' would return 2, etc. i'm trying to accomplish this using an accumulator, here's what i've got: pyindex :: Eq a =3D> a -> [a] -> Maybe Int pyindex c l =3D pyindex' 0 chr (x:xs) where pyindex' count chr (x:xs) =3D do if x =3D=3D chr=20 then return count else pyindex' (count + 1) chr xs now, i know i've got a syntax problem, because i'm pretty sure my logic is correct (or at least MOSTLY correct). can anybody see what's wrong with my stuff? thanks! --=20 Brett Kelly bkelly@sourcereview.net This message has been digitally autographed using GnuPG. Vim - this ain't your daddy's text editor http://www.vim.org --1UWUbFP1cBYEclgG Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQE+87Oea7gYa9SI8SoRAq32AJ0cShOd6W6PnaFjTQyit6GvQx1hCwCgjNNN A8IvsovD7aELRY4nhthT9fY= =9TXQ -----END PGP SIGNATURE----- --1UWUbFP1cBYEclgG-- From m@mlcastle.net Sat Jun 21 02:47:54 2003 From: m@mlcastle.net (mike castleman) Date: Fri, 20 Jun 2003 21:47:54 -0400 Subject: Using an accumulator, "iterating"... In-Reply-To: <20030621012342.GB1797@inkedmn.homelinux.org> References: <20030621012342.GB1797@inkedmn.homelinux.org> Message-ID: <20030621014754.GC1010@pinetree.mlcastle.net> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Fri, Jun 20, 2003 at 06:23:42PM -0700, Brett Kelly wrote: > now, i know i've got a syntax problem, because i'm pretty sure my logic is > correct (or at least MOSTLY correct). Try: pyindex :: Eq a => a -> [a] -> Maybe Int pyindex c l = pyindex' 0 l where pyindex' _ [] = Nothing pyindex' n (x:xs) = if (x == c) then Just n else pyindex' (n+1) xs then, in ghci: Pyindex> pyindex 'e' "brett" Just 2 Pyindex> pyindex 'm' "brett" Nothing Pyindex> pyindex 't' "brett" Just 3 hope this helps. mike - -- mike castleman / m at mlcastle dot net / http://mlcastle.net / (646) 382-7220 aolim: mlcastle / icq: 3520821 / yahoo: mlc000 please avoid sending me microsoft word, excel, or powerpoint documents. see http://www.gnu.org/philosophy/no-word-attachments.html for more info. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.1 (GNU/Linux) iD8DBQE+87lKrbXc6n5AevkRAtHwAJ9ARgtMHxWmlHWdgvOmIOFdi0W6FwCeOnLk TXyz94uSH3RufPx7xpZhtX4= =98Ym -----END PGP SIGNATURE----- From glynn.clements@virgin.net Sat Jun 21 02:46:09 2003 From: glynn.clements@virgin.net (Glynn Clements) Date: Sat, 21 Jun 2003 02:46:09 +0100 Subject: Using an accumulator, "iterating"... In-Reply-To: <20030621012342.GB1797@inkedmn.homelinux.org> References: <20030621012342.GB1797@inkedmn.homelinux.org> Message-ID: <16115.47329.597454.438857@cerise.nosuchdomain.co.uk> Brett Kelly wrote: > I'm trying to write a function that takes a list and a element (same type) and > returns the index of the first instance of the element in the list. like: > getindex "brett" 'e' would return 2, etc. > > i'm trying to accomplish this using an accumulator, here's what i've got: > > pyindex :: Eq a => a -> [a] -> Maybe Int > pyindex c l = pyindex' 0 chr (x:xs) None of chr, x or xs are defined here; if you change the above line to: pyindex c l = pyindex' 0 c l it works. Except that you will get a match failure if the list doesn't contain the specified element, so you also need a base case: pyindex' _ _ [] = Nothing -- Glynn Clements From bkelly@sourcereview.net Sat Jun 21 03:02:09 2003 From: bkelly@sourcereview.net (Brett Kelly) Date: Fri, 20 Jun 2003 19:02:09 -0700 Subject: Using an accumulator, "iterating"... In-Reply-To: <20030621014754.GC1010@pinetree.mlcastle.net> References: <20030621012342.GB1797@inkedmn.homelinux.org> <20030621014754.GC1010@pinetree.mlcastle.net> Message-ID: <20030621020209.GC1797@inkedmn.homelinux.org> --NU0Ex4SbNnrxsi6C Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Awesome, thanks! Sometime around Fri, Jun 20, 2003 at 09:47:54PM -0400, mike castleman said: > On Fri, Jun 20, 2003 at 06:23:42PM -0700, Brett Kelly wrote: > > now, i know i've got a syntax problem, because i'm pretty sure my logic= is > > correct (or at least MOSTLY correct). >=20 > Try: >=20 > pyindex :: Eq a =3D> a -> [a] -> Maybe Int > pyindex c l =3D pyindex' 0 l > where pyindex' _ [] =3D Nothing > pyindex' n (x:xs) =3D if (x =3D=3D c) > then Just n > else pyindex' (n+1) xs >=20 >=20 > then, in ghci: > Pyindex> pyindex 'e' "brett" > Just 2 > Pyindex> pyindex 'm' "brett" > Nothing > Pyindex> pyindex 't' "brett" > Just 3 >=20 > hope this helps. > mike >=20 > --=20 > mike castleman / m at mlcastle dot net / http://mlcastle.net / (646) 382-= 7220 > aolim: mlcastle / icq: 3520821 / yahoo: mlc000 > please avoid sending me microsoft word, excel, or powerpoint documents. > see http://www.gnu.org/philosophy/no-word-attachments.html for more info. > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe --=20 Brett Kelly bkelly@sourcereview.net This message has been digitally autographed using GnuPG. Open Source software will continue to change the world... http://www.opensource.org --NU0Ex4SbNnrxsi6C Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQE+87yha7gYa9SI8SoRAsqlAJ4ikvHqHTuFB3pDo+fpuvNMmptrGwCfXwiD FGLX3xSCe/EQPR8DESjq16o= =oH5Z -----END PGP SIGNATURE----- --NU0Ex4SbNnrxsi6C-- From yu-@div.club.ne.jp Sat Jun 21 03:15:17 2003 From: yu-@div.club.ne.jp (Koji Nakahara) Date: Sat, 21 Jun 2003 11:15:17 +0900 Subject: Help: Stack-overflow and tail-recursive functions In-Reply-To: <935F630FDD8A7F4CB1A0412C7CA4371405ED06C2@RED-MSG-10.redmond.corp.microsoft.com> References: <935F630FDD8A7F4CB1A0412C7CA4371405ED06C2@RED-MSG-10.redmond.corp.microsoft.com> Message-ID: <20030621111517.23dcc30b.yu-@div.club.ne.jp> On Fri, 20 Jun 2003 07:54:50 -0700 "Hal Daume" wrote: > mine didn't either, until I increased the "200" to around "1500"...it's > probably OS/memory specific. Only 600 causes the stack overflow in my environment(FreeBSD, 640MB). Interestingly, on GHCi, the program shows the elements which are constructed from the first row of the matrix, "rests awhile" and then stack overflows (n >= 600) or continues fine (n <= 500). With the improved definition of rmat I wrote in my last mail (Subject: listArray and stack overflow (Re: Help: Stack-overflow and tail-recursive functions)) it runs without both that rest and stack overflow (at least n <= 2000). From agold@bga.com Sat Jun 21 02:41:31 2003 From: agold@bga.com (Artie Gold) Date: Fri, 20 Jun 2003 20:41:31 -0500 Subject: Using an accumulator, "iterating"... References: <20030621012342.GB1797@inkedmn.homelinux.org> Message-ID: <3EF3B7CB.9040407@bga.com> Brett Kelly wrote: > Hello all, > > I'm trying to write a function that takes a list and a element (same type) and > returns the index of the first instance of the element in the list. like: > getindex "brett" 'e' would return 2, etc. > > i'm trying to accomplish this using an accumulator, here's what i've got: > > pyindex :: Eq a => a -> [a] -> Maybe Int > pyindex c l = pyindex' 0 chr (x:xs) > where pyindex' count chr (x:xs) = do > if x == chr > then return count > else pyindex' (count + 1) chr xs > > now, i know i've got a syntax problem, because i'm pretty sure my logic is > correct (or at least MOSTLY correct). > > can anybody see what's wrong with my stuff? > Sure. Three comments: 1) You don't need (or want) the `do' -- that's used for dealing with monads. 2) The function's signature indicates a return type of `Maybe Int', yet you're trying to return an Int. 3) What if you _don't_ find the target? Additional comments: The `if...then...else' form may not be the clearest way -- or the most `Haskell-ish' way of expressing this computation. You may want to look through the standard prelude to find how things like this are usually done. Good luck and HTH, --ag -- Artie Gold -- Austin, Texas From wolfgang@jeltsch.net Sat Jun 21 13:33:51 2003 From: wolfgang@jeltsch.net (Wolfgang Jeltsch) Date: Sat, 21 Jun 2003 14:33:51 +0200 Subject: Using an accumulator, "iterating"... In-Reply-To: <20030621012342.GB1797@inkedmn.homelinux.org> References: <20030621012342.GB1797@inkedmn.homelinux.org> Message-ID: <200306211433.51581.wolfgang@jeltsch.net> On Saturday, 2003-06-21, 03:23, CEST, Brett Kelly wrote: > Hello all, > > I'm trying to write a function that takes a list and a element (same type) > and returns the index of the first instance of the element in the list. > like: getindex "brett" 'e' would return 2, etc. > > i'm trying to accomplish this using an accumulator, here's what i've got: > > pyindex :: Eq a => a -> [a] -> Maybe Int > pyindex c l = pyindex' 0 chr (x:xs) > where pyindex' count chr (x:xs) = do > if x == chr > then return count > else pyindex' (count + 1) chr xs > > now, i know i've got a syntax problem, because i'm pretty sure my logic is > correct (or at least MOSTLY correct). > > can anybody see what's wrong with my stuff? > > thanks! Hello, I think, the following code, which uses certain prelude functions, would be clearer and more elegant: pyindex :: Eq a => a -> [a] -> Maybe Int pyindex c l = lookup c (zip l [0 ..]) I would it generally consider better style to not do recursion explicitely but use the recursion already provided by predefined functions like lookup. Wolfgang From mark@chaos.x-philes.com Sat Jun 21 13:38:48 2003 From: mark@chaos.x-philes.com (Mark Carroll) Date: Sat, 21 Jun 2003 08:38:48 -0400 (EDT) Subject: Assembling lists start-to-end Message-ID: I am assembling a list from start to end. I can add elements to the end with "previous ++ [current]" or I can add them with "current : previous" and reverse it when I'm done. Or, maybe I should use some other data structure. (I don't know the length in advance.) Any thoughts? -- Mark From wolfgang@jeltsch.net Sat Jun 21 13:47:22 2003 From: wolfgang@jeltsch.net (Wolfgang Jeltsch) Date: Sat, 21 Jun 2003 14:47:22 +0200 Subject: Assembling lists start-to-end In-Reply-To: References: Message-ID: <200306211447.22962.wolfgang@jeltsch.net> On Saturday, 2003-06-21, 14:38, CEST, Mark Carroll wrote: > I am assembling a list from start to end. I can add elements to the end with > "previous ++ [current]" or I can add them with "current : previous" and > reverse it when I'm done. Or, maybe I should use some other data structure. > (I don't know the length in advance.) Any thoughts? > > -- Mark Hi, adding with "current : previous" and finally reversing the list seems good since the whole process takes linear time whereas adding to the end with "previous ++ [current]" would take quadratic time. Wolfgang From tweed@compsci.bristol.ac.uk Sat Jun 21 14:21:20 2003 From: tweed@compsci.bristol.ac.uk (D. Tweed) Date: Sat, 21 Jun 2003 14:21:20 +0100 (BST) Subject: Assembling lists start-to-end In-Reply-To: <200306211447.22962.wolfgang@jeltsch.net> Message-ID: On Sat, 21 Jun 2003, Wolfgang Jeltsch wrote: > On Saturday, 2003-06-21, 14:38, CEST, Mark Carroll wrote: > > I am assembling a list from start to end. I can add elements to the end with > > "previous ++ [current]" or I can add them with "current : previous" and > > reverse it when I'm done. Or, maybe I should use some other data structure. > > (I don't know the length in advance.) Any thoughts? [snip] > adding with "current : previous" and finally reversing the list seems good > since the whole process takes linear time whereas adding to the end with > "previous ++ [current]" would take quadratic time. Another thing to consider is whether the list is both likely to be very, very long & you will be processing the list in a way in which groups of items at the top of the list are dealt with in small groups, so that lazy evaluation would make it desirable not to have to fully construct the list before processing any of it (and potentially removed, thus reducing memory & hence requiring less garbage collecting). In this case, it _may_ be better to build it up in a lazy-evaluation friendly way using functions f,g,... of the form f args=current:g args' where (current,args')=.... However, it may (a) not be possible to build it up that way and (b) depending on the size of the datastructures in args, this approach may make memory usage worse by requiring these big structures to be kept for longer whereas if the list were built all at once it could be garbage collected much quicker. Just a random thought basically saying `it sometimes of depends what you're going to do with the list' ___cheers,_dave_________________________________________________________ www.cs.bris.ac.uk/~tweed/ | `It's no good going home to practise email:tweed@cs.bris.ac.uk | a Special Outdoor Song which Has To Be work tel:(0117) 954-5250 | Sung In The Snow' -- Winnie the Pooh From naudts_vannoten@yahoo.com Sat Jun 21 16:34:59 2003 From: naudts_vannoten@yahoo.com (naudts guido) Date: Sat, 21 Jun 2003 08:34:59 -0700 (PDT) Subject: IO system Message-ID: <20030621153459.78768.qmail@web40505.mail.yahoo.com> Hallo, Take following function: f::Array Int Char -> (Array Int Char, Char) f array = (array1, c) where c = array!1 array1 = array//[(2,'b')] and also following function: f::Direct_access_file -> (Direct_access_file, Char) f daf = (daf1, c) where c = getnext daf daf1 = set 2 'b' with a hypothetical format for the direct access file. Now I can certainly implement the first function in Haskell but not the second. Now the only difference between the two functions is the location of the data: in the first the data of the array are in RAM, in the second the data of the direct access file are on disk. There is no other difference. As far as referential integrity is concerened I don't see any difference too. So why can I implement the first function and not the second (well I can use direct access files but I have to change the type of my function.The problem is: I do not see why the location of data should have an influence here. Greetings, __________________________________ Do you Yahoo!? SBC Yahoo! DSL - Now only $29.95 per month! http://sbc.yahoo.com From glynn.clements@virgin.net Sat Jun 21 17:34:59 2003 From: glynn.clements@virgin.net (Glynn Clements) Date: Sat, 21 Jun 2003 17:34:59 +0100 Subject: IO system In-Reply-To: <20030621153459.78768.qmail@web40505.mail.yahoo.com> References: <20030621153459.78768.qmail@web40505.mail.yahoo.com> Message-ID: <16116.35123.214786.761947@cerise.nosuchdomain.co.uk> naudts guido wrote: > Take following function: > > f::Array Int Char -> (Array Int Char, Char) > f array = (array1, c) > where c = array!1 > array1 = array//[(2,'b')] > > and also following function: > f::Direct_access_file -> (Direct_access_file, Char) > f daf = (daf1, c) > where c = getnext daf > daf1 = set 2 'b' > > with a hypothetical format for the direct access file. > Now I can certainly implement the first function in > Haskell but not the second. > Now the only difference between the two functions is > the location of the data: in the first the data of the > array are in RAM, in the second the data of the direct > access file are on disk. There is no other difference. > As far as referential integrity is concerened I don't > see any difference too. > So why can I implement the first function and not the > second (well I can use direct access files but I have > to change the type of my function.The problem is: > I do not see why the location of data should have an > influence here. Haskell values are private to the program, while file contents may be read and written by other processes. Haskell computations can be deferred, omitted or duplicated so long as the program's semantics are preserved, but I/O operations must be performed as and when specified. -- Glynn Clements From glynn.clements@virgin.net Sat Jun 21 17:22:05 2003 From: glynn.clements@virgin.net (Glynn Clements) Date: Sat, 21 Jun 2003 17:22:05 +0100 Subject: Using an accumulator, "iterating"... In-Reply-To: <3EF3B7CB.9040407@bga.com> References: <20030621012342.GB1797@inkedmn.homelinux.org> <3EF3B7CB.9040407@bga.com> Message-ID: <16116.34349.440090.661496@cerise.nosuchdomain.co.uk> Artie Gold wrote: > > I'm trying to write a function that takes a list and a element (same type) and > > returns the index of the first instance of the element in the list. like: > > getindex "brett" 'e' would return 2, etc. > > > > i'm trying to accomplish this using an accumulator, here's what i've got: > > > > pyindex :: Eq a => a -> [a] -> Maybe Int > > pyindex c l = pyindex' 0 chr (x:xs) > > where pyindex' count chr (x:xs) = do > > if x == chr > > then return count > > else pyindex' (count + 1) chr xs > > > > now, i know i've got a syntax problem, because i'm pretty sure my logic is > > correct (or at least MOSTLY correct). > > > > can anybody see what's wrong with my stuff? > > > Sure. > Three comments: > > 1) You don't need (or want) the `do' -- that's used for dealing with > monads. > > 2) The function's signature indicates a return type of `Maybe Int', yet > you're trying to return an Int. Maybe *is* a monad: instance Monad Maybe where Just x >>= k = k x Nothing >>= k = Nothing return = Just fail s = Nothing Having said that, treating it as such doesn't really have any benefit here. -- Glynn Clements From duncan@coutts.uklinux.net Sat Jun 21 18:02:53 2003 From: duncan@coutts.uklinux.net (Duncan Coutts) Date: Sat, 21 Jun 2003 18:02:53 +0100 Subject: IO system In-Reply-To: <16116.35123.214786.761947@cerise.nosuchdomain.co.uk> References: <20030621153459.78768.qmail@web40505.mail.yahoo.com> <16116.35123.214786.761947@cerise.nosuchdomain.co.uk> Message-ID: <20030621180253.4eb29bce.duncan@coutts.uklinux.net> On Sat, 21 Jun 2003 17:34:59 +0100 Glynn Clements wrote: > > I do not see why the location of data should have an > > influence here. > > Haskell values are private to the program, while file contents may be > read and written by other processes. > > Haskell computations can be deferred, omitted or duplicated so long as > the program's semantics are preserved, but I/O operations must be > performed as and when specified. There are some special cases where you could get away with it when the IO system gives us enough guarantees. You'd have to be very careful however, to preserve the right semantics. For example if you could mmap() a file such that changes to the underlying file were not reflected in the mmap()d region then you could lazily defer reads from the file. (Unfortunatley MAP_PRIVATE doesn't quite give this.) Duncan From t-hald@microsoft.com Sat Jun 21 20:34:16 2003 From: t-hald@microsoft.com (Hal Daume) Date: Sat, 21 Jun 2003 12:34:16 -0700 Subject: Assembling lists start-to-end Message-ID: <935F630FDD8A7F4CB1A0412C7CA4371405ED06CF@RED-MSG-10.redmond.corp.microsoft.com> sorry, forgot to send this to the list: Another way to do it is to use accumulating lists. As a simple example, let's consider: > myf p l =3D reverse (filter p l) (myf Char.isUpper "Hello Cruel World" =3D=3D> "WCH") that is, it returns elements of a list which match the predicate in reverse order. we could write this very slowly using explicit recursion as: > myf2 p [] =3D [] > myf2 p (x:xs) > | p x =3D myf2 p xs ++ [x] > | otherwise =3D myf2 p xs but traversing the recusive list is very slow. we might induce tail recursion in something like: > myf3 p l =3D myf3' l [] > where > myf3' [] acc =3D acc > myf3' (x:xs) acc =3D myf3' xs (x:acc) Now, the accumulator 'acc' holds the value we're going to return at the end. So this is pretty much what you want. Now, suppose we're just doing filter without the reversing, but we still want it to be tail recursive. We might think we have to write: > myf4 p l =3D reverse (myf3' l []) (where myf3' is as before) this is not so. We can have fun with function composition. What we do is change the accumulator from a list to a function from a list to a list. > myf4 p l =3D myf4' l id > where > myf4' [] acc =3D acc [] > myf4' (x:xs) acc > | p x =3D myf4' xs (\l -> acc (x:l)) > | otherwise =3D myf4' xs acc here, we start out the accumulator as the identity function. to add an element to it, we make a function which takes the old list, adds 'x' to the front and then applies the accumulator. in the base case, we simply apply the empty list to the accumulator function. the second-to-last line can be rewritten a bit more conveniently as: > | p x =3D myf4' xs (acc . (x:)) the neat thing about this is that you can easily change the way the list goes. as it is, we have filter, but if we flip the order for (.), as in: > | p x =3D myf4' xs ((x:) . acc) then we get (reverse . filter). HTH - Hal -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume > -----Original Message----- > From: haskell-cafe-admin@haskell.org=20 > [mailto:haskell-cafe-admin@haskell.org] On Behalf Of Mark Carroll > Sent: Saturday, June 21, 2003 5:39 AM > To: haskell-cafe@haskell.org > Subject: Assembling lists start-to-end >=20 >=20 > I am assembling a list from start to end. I can add elements=20 > to the end > with "previous ++ [current]" or I can add them with "current=20 > : previous" > and reverse it when I'm done. Or, maybe I should use some other data > structure. (I don't know the length in advance.) Any thoughts? >=20 > -- Mark >=20 > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe >=20 From ashley@semantic.org Sun Jun 22 01:40:57 2003 From: ashley@semantic.org (Ashley Yakeley) Date: Sat, 21 Jun 2003 17:40:57 -0700 Subject: MacOS X Project Builder and Haskell Message-ID: Does anyone else use Project Builder with Haskell? Once you fiddle around with it a bit, it seems to work OK with makefiles. But I wondered if anyone had any Haskell-specific extensions? -- Ashley Yakeley, Seattle WA From ashley@semantic.org Mon Jun 23 10:11:01 2003 From: ashley@semantic.org (Ashley Yakeley) Date: Mon, 23 Jun 2003 02:11:01 -0700 Subject: MacOS X Project Builder and Haskell References: Message-ID: I wrote: > Does anyone else use Project Builder with Haskell? Once you fiddle > around with it a bit, it seems to work OK with makefiles. But I wondered > if anyone had any Haskell-specific extensions? OK, I made some spec files for recognising the existence of Haskell source files (single-click in file view) and doing syntax colouring: Put them both in one of these directories: ~/Developer/ProjectBuilder Extras/Specifications/ /Developer/ProjectBuilder Extras/Specifications/ I've put in PB projects in both HBase and HScheme CVS. Of course both of them use "legacy Makefile" targets as I also want to build without PB. Otherwise PB uses Peforce's "jam" (replacement for make) as its build system, using clever regexes to recover warning and error messages from tools. So theoretically it should be possible to integrate GHC directly. -- Ashley Yakeley, Seattle WA From mark@felinemail.zzn.com Mon Jun 23 14:13:09 2003 From: mark@felinemail.zzn.com (Mark Espinoza) Date: Mon, 23 Jun 2003 08:13:09 -0500 Subject: Haskell-Cafe digest, Vol 1 #730 - 5 msgs Message-ID:

Hello,

 I am thinking about learning Haskell and rewriting my shopping cart,
which I have written very poorly in perl, in Haskell. I already have
GHC installed on my web server and personal computer. Is this a good
or bad idea? Does Haskell have anything like perl's CGI module? What
are the advantages of Haskell over Lisp? (I already have a couple of
Lisp books because I was looking into lisp when I discovered Haskell.)
I much prefer to learn from books rather than electronic media, so
what books could I use. Besides basic Haskell information, I would be
interested in any networking or CGI specific Haskell books.

Thanks in advance.

Sincerely,

Mark



Get your free e-mail address at http://felinemail.zzn.com
___________________________________________________________
Get your own Web-based E-mail Service at http://www.zzn.com

From GK@ninebynine.org Mon Jun 23 15:26:14 2003 From: GK@ninebynine.org (Graham Klyne) Date: Mon, 23 Jun 2003 15:26:14 +0100 Subject: Learning Haskell (was: Haskell-Cafe digest, Vol 1 #730 - 5 msgs) In-Reply-To: Message-ID: <5.1.0.14.2.20030623142236.02fca838@127.0.0.1> At 08:13 23/06/03 -0500, Mark Espinoza wrote: > I am thinking about learning Haskell and rewriting my shopping cart, >which I have written very poorly in perl, in Haskell. I already have >GHC installed on my web server and personal computer. Is this a good >or bad idea? Does Haskell have anything like perl's CGI module? What >are the advantages of Haskell over Lisp? (I already have a couple of >Lisp books because I was looking into lisp when I discovered Haskell.) I'll respond from the perspective of a relatively recent comer to Haskell. The big win, to my mind, of using Haskell over other "rapid" programming languages/environments is its type safety, which I would think is a real advantage for an e-commerce application, where (I presume) security is a concern, and the expressive power of higher order functions. I have found the quality of language implementations and basic libraries to be excellent. I use Hugs and GHC. A possible drawback is that the support for web applications may be immature compared with, say, Perl. (Others may offer different opinions, but I note that it's only very recently that there has been an XML parser for Haskell supporting XML namespaces.) In order to develop a serious web application, you'll need to come to terms with Haskell's way of doing I/O. It's fully capable, and really quite powerful, but it does take some time to get one's head around when coming from a more conventional programming background. >I much prefer to learn from books rather than electronic media, so >what books could I use. Besides basic Haskell information, I would be >interested in any networking or CGI specific Haskell books. I don't know of any networking-specific Haskell books. Once you have a reasonable command of the basic language, Haskell support libraries tend to be very easy to understand use, in my experience. Materials I have found useful include: The Craft of Functional Programming, Simon Thompson -- it starts a little slowly for my taste, but the later sections are packed with useful information relevant to Haskell programming technique. I found a few gaps in coverage of the Haskell language, so it's not always useful as a reference. Haskell 98 Language and Libraries, The Revised Report, Simon Peyton-Jones -- this is essentially the same as the Haskell reference material available at Haskell.org, but I really find it to be more accessible in book form. Pure Functional Data Structures, Chris Okasaki -- I found this was useful not so much for the purpose suggested by its title, but because it gives insights into programming style/techniques that work with a functional programming language. Unfortunately, the book's "first language" is Standard ML, and you have to look to an appendix for Haskell code examples. I'd suggest looking at this after you have a feel for basic Haskell language structures, for some guidance on how to use them. ... Those happen to be the Haskell books I have, and they've all been useful to me. There are others which may be better. There is also a wealth of material available on the web in the form of conference papers, etc. Some of this is pretty academic computer science, but some that I have found useful at a practical level are (sorry no URIs, but Google should find most of these, especially if combined with the keyword "Haskell"): GHC manual and libraries; chapter 7 discusses some important language extensions that are not yet part of the standard. In particular, section 7.8 introduces Multiparameter type classes (see also Type classes, exploring the design space, which is cited there). State in Haskell, John Launchbury and Simon Peyton-Jones: I found this to be one of the more illuminating introductions to Monads (which are central to Haskell I/O). Why Functional Programming Matters, John Hughes: this gives some good indicators as to whjy you might use a language like Haskell, which in turn suggests styles of programming that best leverage Haskell's strengths. Scrap Your Boilerplate, Ralf Lammel and Simon Peyton-Jones: for me, even though it describes features not yet present in standard Haskell, this serves as a continuation of the John Hughes paper, suggesting the kind of coding advantages one may seek to gain from a functional language like Haskell. (A message I read into this is that higher order functions provide a way to achieve the advantages of something like C++ Standard Template Library, without compromising type safety in the ways that STL can entail, and some hints about how to achieve that.) ... Coming from many years of using conventional programming languages (Pascal, C, C++, Java, Python, ... ) I've found the Haskell learning curve to be quite steep (but then again, I found Perl to be quite difficult, with it's irregular structure and its many ways to do any given thing). The type system is both very powerful and sometimes very subtle, but once you start coming to terms with it, it is really helpful in picking up logical flaws in one's code ... at compile time. Learning to use higher order functions effectively also takes some mental recalibration. For all the new ideas to be learned, I am now finding that Haskell amply repays the effort in elegant, easily constructed and reliable code. #g -- PS: I maintain a few Haskell-related links at: http://www.ninebynine.org/Links.html#Programming-Haskell ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From Malcolm.Wallace@cs.york.ac.uk Mon Jun 23 17:34:24 2003 From: Malcolm.Wallace@cs.york.ac.uk (Malcolm Wallace) Date: Mon, 23 Jun 2003 17:34:24 +0100 Subject: ANNOUNCE: hmake-3.08 Message-ID: <20030623173424.2584dbb3.Malcolm.Wallace@cs.york.ac.uk> hmake-3.08 ---------- http://www.haskell.org/hmake/ We announce a new release of hmake, the compilation manager for Haskell. This is essentially a bugfix release, to enable hmake to build cleanly with ghc versions >= 6.0. * Hmake should now build cleanly with GHC 6.0. * In hmake-interactive, if the readline library is not available, the replacement simple line editor now has a history mechanism. Regards, Malcolm From listman@garbett.org Tue Jun 24 21:24:01 2003 From: listman@garbett.org (Shawn P. Garbett) Date: Tue, 24 Jun 2003 15:24:01 -0500 Subject: Shoot self in foot Message-ID: <200306241524.01743.listman@garbett.org> Based on the earlier posted joke on this list, I put together the following code. Could probably use a bit of simplification, but you get the picture. import IO import GHC.IOBase -- True = nice foot, False = shot up by some lunatic type Foot = Bool -- Manage a request from the user, given request and current foot state manage :: Char -> Foot -> IO Foot manage c foot -- InterleaveIO Makes the request "lazy" | c == '1' = unsafeInterleaveIO $ do putStr "OUCH!!!! Shoot Self in Foot\n" return False -- The foot is now shot -- The doctor examines the state of the foot variable | c == '2' = do putStr "Doctor examines foot\n" if foot then putStr "I have a good foot.\n" else putStr "I have a shot-up foot.\n" return foot -- Otherwise just keep processing | otherwise = do return foot -- Main processing loop process :: Foot -> IO () process f = do c <- getChar -- Get a character putChar '\n' -- Return to keep the screen neat if c == '0' -- Is it an exit? then return () -- then leave else do f' <- manage c f -- otherwise manage request process f' -- continue to process -- Little usage message usage :: IO () usage = do putStr "0. Exit Program\n" putStr "1. Pull Trigger\n" putStr "2. Call Doctor\n" -- Main routine main :: IO () main = do usage -- Print usage process True -- Start processing with a good foot From rvollmert@gmx.net Wed Jun 25 12:33:07 2003 From: rvollmert@gmx.net (Robert Vollmert) Date: Wed, 25 Jun 2003 13:33:07 +0200 Subject: "callbacks" in Haskell Message-ID: <20030625113307.GA7312@krikkit> Hello, I've been having a little trouble writing a module that waits for and handles IO events, e.g. by reading from a pipe. It seemed natural to use some form of callbacks here, though that may very well be the wrong approach. I'd be happy to hear of alternatives. Anyway, I got a callback-based approach to work to some extent, but am not happy with the callback's type. The abstract form of this module is as follows. I'd appreciate any input. A class that specifies what we expect of the base monad. > class (Monad m) => MonadReq m A class that specifies what we provide to the callback. > class (Monad m) => MonadProv m The module's main function. > f :: (MonadReq m) => Callback m a -> m a > f c = ... Internally, we wrap the base monad with some monad transformer, say > data InternalT m a = ... with > instance MonadTrans InternalT so that the callback can access the base monad, and > instance (MonadReq m) => MonadProv (InternalT m) so that we can actually provide MonadProv. A type for callback that works is > type Callback m a = InternalT m a What I don't like about this is that we shouldn't really need to expose what exact monad transformer we use. Also, if we added a second function that also runs the callback in a MonadProv but that uses a different transformer (for instance, needing to keep track of some extra state), we'd need a new callback type. What seems to be the right type is > type Callback m a = forall t. (MonadTrans t, MonadProv (t m)) => t m a which sort of works with '-fglasgow-exts' (what's this extension called?). However, it seems to cause all kinds of problems, e.g. pairs of this type appear to be illegal. Cheers Robert From ozone@algorithm.com.au Wed Jun 25 19:51:49 2003 From: ozone@algorithm.com.au (Andre Pang) Date: Wed, 25 Jun 2003 11:51:49 -0700 Subject: MacOS X Project Builder and Haskell In-Reply-To: Message-ID: <142DC4BF-A73E-11D7-A5FC-000393C79D34@algorithm.com.au> On Monday, June 23, 2003, at 02:11 AM, Ashley Yakeley wrote: > I wrote: > >> Does anyone else use Project Builder with Haskell? Once you fiddle >> around with it a bit, it seems to work OK with makefiles. But I >> wondered >> if anyone had any Haskell-specific extensions? > > OK, I made some spec files for recognising the existence of Haskell > source files (single-click in file view) and doing syntax colouring: > > > Put them both in one of these directories: > ~/Developer/ProjectBuilder Extras/Specifications/ > /Developer/ProjectBuilder Extras/Specifications/ > > I've put in PB projects in both HBase and HScheme CVS. Of course both > of > them use "legacy Makefile" targets as I also want to build without PB. > Otherwise PB uses Peforce's "jam" (replacement for make) as its build > system, using clever regexes to recover warning and error messages from > tools. So theoretically it should be possible to integrate GHC > directly. Hi Ashley, I guess you've heard of the announcements of the new Apple IDE announced at WWDC recently ("Xcode"). I'm at WWDC right now, and I'll do my best to talk to the Apple engineers there to make sure that all the infrastructure is in place to be able to integrate Haskell/GHC with Xcode. Xcode does look a little bit more extensible than Project Builder, but since it's in beta, not everything is actually documented/integrated yet (in particular, its native build system). However, if you still want to use Project Builder, I have managed to get GHC integration going. It's not pretty (put it this way: Perl is involved ...), but it _does_ work. I'm planning to release it in ~2 weeks, but if you can't wait, email me back and I'll give you a preview if I have time :). -- % Andre Pang : just.your.average.bounty.hunter -- % Andre Pang : trust.in.love.to.save From Tom.Pledger@peace.com Wed Jun 25 21:44:38 2003 From: Tom.Pledger@peace.com (Tom Pledger) Date: Thu, 26 Jun 2003 08:44:38 +1200 Subject: "callbacks" in Haskell In-Reply-To: <20030625113307.GA7312@krikkit> References: <20030625113307.GA7312@krikkit> Message-ID: <16122.2486.166435.493423@tux-17.corp.peace.com> Robert Vollmert writes: | Hello, | | I've been having a little trouble writing a module that waits for and | handles IO events, e.g. by reading from a pipe. It seemed natural to | use some form of callbacks here, though that may very well be the | wrong approach. I'd be happy to hear of alternatives. | | Anyway, I got a callback-based approach to work to some extent, but | am not happy with the callback's type. : Can the event and handler inhabit the same monad, say IO? If so, is the following the sort of thing you had in mind? waitAndHandleOneEvent :: IO e -> (e -> IO ()) -> IO () waitAndHandleOneEvent ioe h = forkIO (do e <- ioe h e) But then, because ioe and h always get combined the same way (ioe >>= h), we can generalise waitAndHandleOneEvent to waitAndDoOneThing :: IO () -> IO () waitAndDoOneThing io = forkIO io which is equivalent to using forkIO directly, as in do ... let ioe :: IO MyEvent ioe = ... h :: MyEvent -> IO () h e = ... forkIO (ioe >>= h) ... HTH. Tom From ashley@semantic.org Thu Jun 26 03:29:34 2003 From: ashley@semantic.org (Ashley Yakeley) Date: Wed, 25 Jun 2003 19:29:34 -0700 Subject: MacOS X Project Builder and Haskell Message-ID: <200306260229.TAA02487@mail4.halcyon.com> At 2003-06-25 11:51, Andre Pang wrote: >Hi Ashley, I guess you've heard of the announcements of the new Apple >IDE announced at WWDC recently ("Xcode"). I'm at WWDC right now, and >I'll do my best to talk to the Apple engineers there to make sure that >all the infrastructure is in place to be able to integrate Haskell/GHC >with Xcode. Xcode does look a little bit more extensible than Project >Builder, but since it's in beta, not everything is actually >documented/integrated yet (in particular, its native build system). The (reduced) screen-shots of Xcode on the Apple site are so pretty I was worrying whether it would actually be as powerful as PB, which I'm fairly impressed with. I'm delighted to hear that Xcode will be even more extensible. >However, if you still want to use Project Builder, I have managed to >get GHC integration going. It's not pretty (put it this way: Perl is >involved ...), but it _does_ work. I'm planning to release it in ~2 >weeks, but if you can't wait, email me back and I'll give you a preview >if I have time :). All my Haskell development is cross-platform at the moment, so I must use makefiles and thus "legacy" targets anyway. Though I'm sure I'll have a look at it when you've finished with it... Actually my biggest build problem at the moment is that the version of make that comes with the system is buggy. I use the make that comes with fink, but of course not everyone has that installed. Perhaps this will be fixed in the new Darwin. -- Ashley Yakeley, Seattle WA Almost empty page: From rvollmert@gmx.net Thu Jun 26 11:33:22 2003 From: rvollmert@gmx.net (Robert Vollmert) Date: Thu, 26 Jun 2003 12:33:22 +0200 Subject: "callbacks" in Haskell In-Reply-To: <16122.2486.166435.493423@tux-17.corp.peace.com> References: <20030625113307.GA7312@krikkit> <16122.2486.166435.493423@tux-17.corp.peace.com> Message-ID: <20030626103322.GA2153@krikkit> Tom Pledger wrote: > Robert Vollmert writes: > | I've been having a little trouble writing a module that waits for and > | handles IO events, e.g. by reading from a pipe. It seemed natural to > | use some form of callbacks here, though that may very well be the > | wrong approach. I'd be happy to hear of alternatives. > Can the event and handler inhabit the same monad, say IO? If so, is > the following the sort of thing you had in mind? > > waitAndHandleOneEvent :: IO e -> (e -> IO ()) -> IO () > waitAndHandleOneEvent ioe h = forkIO (do e <- ioe > h e) Thanks for your reply. I was really hoping to do this without concurrency, though. Also, since I'd like to keep some extra state in the event loop, I'd like to be able to extend the monad. I'll try to clarify: I'd like to yield control to an IO action, which would run the callback on receiving an event. Like: handleEvents :: (Event -> IO ()) -> IO () handleEvents callback = do e <- getEvent callback e handleEvents callback However, I'd like to * not require IO, but any MonadIO (this shouldn't be a problem, I think) * extend the base monad in my event loop (no problem either) and * allow the callback to access this (which is where it gets difficult) In the case of reading events from a pipe, the extension in b) might consist of storing a handle to the pipe. Then, maybe I'd want to provide (in the extended monad) an action closePipe, which I'd like the callback to be able to call. Cheers Robert From mark@chaos.x-philes.com Thu Jun 26 19:40:51 2003 From: mark@chaos.x-philes.com (Mark Carroll) Date: Thu, 26 Jun 2003 14:40:51 -0400 (EDT) Subject: Simple monads Message-ID: Not really seeing why Unique is in the IO monad, not deeply understanding the use of Haskell extensions in the State source, and wanting to try to learn a bit more about monads, I thought I'd try to write my own monad for the first time: something for producing a series of unique labels. This is how it turned out: ========================================================================== module Label (Label, Labeller, newLabel) where import Monad newtype Label = Label Int deriving (Eq, Ord) newtype Labeller a = Labeller (Int -> (Int, a)) instance Monad Labeller where return r = Labeller (\n -> (n, r)) (Labeller g) >>= y = let f m = let (r, n) = g m Labeller h = y n in h r in Labeller f newLabel :: Labeller Label newLabel = Labeller (\n -> (n + 1, Label n)) runLabeller :: Labeller a -> a runLabeller (Labeller l) = snd (l minBound) labelTest :: Labeller [Int] labelTest = do Label a <- newLabel Label b <- newLabel Label c <- newLabel Label d <- newLabel return [a,b,c,d] main = print (runLabeller labelTest) ========================================================================== I was thinking that maybe, (a) People could point out to me where I'm still confused, as revealed by my code. Is it needlessly complicated? (b) My code may be instructive to someone else. -- Mark From t-hald@microsoft.com Thu Jun 26 19:43:14 2003 From: t-hald@microsoft.com (Hal Daume) Date: Thu, 26 Jun 2003 11:43:14 -0700 Subject: Simple monads Message-ID: <935F630FDD8A7F4CB1A0412C7CA4371405ED06ED@RED-MSG-10.redmond.corp.microsoft.com> > (a) People could point out to me where I'm still confused, as=20 > revealed by > my code. Is it needlessly complicated? looks pretty reasonable to me :) as to why Unique is in the IO monad is probabyl because if it were in any other monad, you could start the monad twice and thus get a repeat of each ID (if that makes sense). The only way around this is to put it in IO. From stein@eecs.harvard.edu Thu Jun 26 22:48:17 2003 From: stein@eecs.harvard.edu (Lex Stein) Date: Thu, 26 Jun 2003 17:48:17 -0400 (EDT) Subject: haskell array access In-Reply-To: <935F630FDD8A7F4CB1A0412C7CA4371405ED06ED@RED-MSG-10.redmond.corp.microsoft.com> References: <935F630FDD8A7F4CB1A0412C7CA4371405ED06ED@RED-MSG-10.redmond.corp.microsoft.com> Message-ID: Hi, I'm measuring Haskell, Ocaml, and C, small array access performance and the results with Haskell (GHC 5.02.2) are so bad that I think I must be doing something wrong. Indeed, I am hardly a seasoned Haskell programmer. My results are: ghc -O 61.60s gcc -O3 0.20s Ocamlopt 1.11s (tail call) Ocamlopt 0.82s (for loop) Why is the ghc generated code so slow? The source for all the tests is below. Any insight will be greatly appreciated (I'm running on Debian Linux w/ 1GHz x86 CPU and 768MB RAM). The test cycles through an array of 16 elements, reading 100*10^6 elements. Thanks! Lex Haskell (ghc5) test source: import Array k = Array.array (0,15) [(i, i+1) | i <- [0 .. 15] ] acc 0 = 0 acc n = seq (k Array.! (n `mod` 16)) (acc (n-1)) main = do print (acc 100000000) C (gcc) test source: int main () { int i, k; int a [16]; for (i=0; i<=100000000; i++) { k = a [i % 16]; } } Ocaml test source (tail call): let a = Array.make 16 0;; let rec do1 i = if (i>100000000) then () else let k = a.(i mod 16) in do1 (i+1);; do1 0;; Ocaml test source (for loop): let a = Array.make 16 0;; for i=0 to 100000000 do let k = a.(i mod 16) in () done From ddarius@hotpop.com Thu Jun 26 22:57:43 2003 From: ddarius@hotpop.com (Derek Elkins) Date: Thu, 26 Jun 2003 17:57:43 -0400 Subject: Simple monads In-Reply-To: References: Message-ID: <20030626175743.00001bf5.ddarius@hotpop.com> On Thu, 26 Jun 2003 14:40:51 -0400 (EDT) Mark Carroll wrote: > Not really seeing why Unique is in the IO monad, What Unique? The one in the GHC source? If so, it seems that it's so you can create multiple unique supplies that don't overlap. Since the unique supply isn't a monad transformer or over IO computations, you couldn't simply stay in one UniqueSupply computation for the whole program. Anyways, it's only creation that is in the IO monad. > not deeply > understanding the use of Haskell extensions in the State source, I'm assuming Control.Monad.State's source in which case -no- extensions are used for -State- (well, at least I don't see any quickly glancing). Extensions are used for the -MonadState class-. For the MonadState class they are pretty much necessary. Multiparameter type classes are necessary because the state type depends on the monad (get would have type forall s.Monad m => m -> s otherwise which is rather meaningless), the function dependencies tell the type checker that the state type is completely determined by the monad type. > and > wanting to try to learn a bit more about monads, I'm not a big supporter of reading (arbitrary) sourcecode to learn a language (at least early on). It isn't aimed at being didactic, there are compromises/irrelevant details/added complexities/hidden assumptions, even if it's well-documented the documentation is still going to assume the reader has a certain level of competence and is not going to document the why or how of day to day things (e.g. accumulating parameters), and finally it may simply be a poor (or at least not polished) example of coding. > I thought I'd try to > write my own monad for the first time: something for producing a > series of unique labels. This is how it turned out: > > ===================================================================== > ===== module Label (Label, Labeller, newLabel) > where > import Monad > > newtype Label = Label Int deriving (Eq, Ord) why not Show as well? > (a) People could point out to me where I'm still confused, as revealed > by my code. Is it needlessly complicated? It could hardly be made simpler, well except for simply wrapping State with appropriate functions/types ;). You may want to watch out for laziness though, e.g. last $ sequence $ replicate 1000 newLabel is Label (1+1+1+1+1+1+1+1+1+...minBound) as opposed to Label (999+minBound) (I'm pretty sure, well modulo what the compiler might do). The simplest fix would be making Int a strict field (adding ! to it) or changing newLabel to n `seq` (n+1,Label n). From Sven.Panne@informatik.uni-muenchen.de Thu Jun 26 23:07:27 2003 From: Sven.Panne@informatik.uni-muenchen.de (Sven Panne) Date: Fri, 27 Jun 2003 00:07:27 +0200 Subject: haskell array access References: <935F630FDD8A7F4CB1A0412C7CA4371405ED06ED@RED-MSG-10.redmond.corp.microsoft.com> Message-ID: <3EFB6E9F.8040709@informatik.uni-muenchen.de> Well, part of the answer is definitely that the Haskell program is the *only* one which really uses the array elements. :-) I guess that the compilers for the other languages simply remove the array access from the generated code (gcc definitely does, only an empty loop remains). Another reason is that the type signatures are missing, so Integer is used instead of Int, which is a bit unfair. Adding k :: Array Int Int acc :: Int -> Int cuts down the time by more than factor 5 on my machine. Cheers, S. From stein@eecs.harvard.edu Thu Jun 26 23:46:26 2003 From: stein@eecs.harvard.edu (Lex Stein) Date: Thu, 26 Jun 2003 18:46:26 -0400 (EDT) Subject: haskell array access In-Reply-To: <3EFB6E9F.8040709@informatik.uni-muenchen.de> References: <935F630FDD8A7F4CB1A0412C7CA4371405ED06ED@RED-MSG-10.redmond.corp.microsoft.com> <3EFB6E9F.8040709@informatik.uni-muenchen.de> Message-ID: Great, thanks. Those suggestions narrow the gap from GHC -O being 330x slower than GCC -O3 to it being 20x slower. Here are the new results: gcc -O3 0.54s ocamlopt 1.11s ghc -O 10.76s ocamlc 14.10s GHC is still pretty slow for native x86 instruction code. Is there any way to further explain the performance gap ? (new code below) Thanks! Lex Haskell (GHC) source: import Array k :: Array Int Int k = Array.array (0,15) [(i, i+1) | i <- [0 .. 15] ] acc :: Int -> Int acc 0 = 0 acc n = seq (k Array.! (n `mod` 16)) (acc (n-1)) main = do print (acc 100000000) Caml test source: let a = Array.make 16 0;; let rec do1 i z = if (i>100000000) then z else do1 (i+1) (z + a.(i mod 16));; do1 0 0;; C (gcc) test source: int main () { int i, k = 0; int a [16]; for (i=0; i<100000000; i++) { k += a [i % 16]; } return (k); } On Fri, 27 Jun 2003, Sven Panne wrote: > Well, part of the answer is definitely that the Haskell program is the > *only* one which really uses the array elements. :-) I guess that the > compilers for the other languages simply remove the array access from > the generated code (gcc definitely does, only an empty loop remains). > > Another reason is that the type signatures are missing, so Integer is > used instead of Int, which is a bit unfair. Adding > > k :: Array Int Int > acc :: Int -> Int > > cuts down the time by more than factor 5 on my machine. > > Cheers, > S. > > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe > From t-hald@microsoft.com Thu Jun 26 23:58:19 2003 From: t-hald@microsoft.com (Hal Daume) Date: Thu, 26 Jun 2003 15:58:19 -0700 Subject: haskell array access Message-ID: <935F630FDD8A7F4CB1A0412C7CA4371405ED06F0@RED-MSG-10.redmond.corp.microsoft.com> This has been hinted to before: gcc gets rid of the loop. bash-2.05b$ gcc -O3 arr.c -S -o arr.s bash-2.05b$ cat arr.s .file "arr.c" .def ___main; .scl 2; .type 32; .endef .text .align 2 .align 16 .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp subl $72, %esp xorl %eax, %eax andl $-16, %esp call __alloca call ___main xorl %eax, %eax .align 16 L7: incl %eax cmpl $100000000, %eax jle L7 leave ret the inside of the loop is exactly: L7: incl %eax cmpl $100000000, %eax jle L7 which doesn't read the array! essentially you are being unfare to ghc by making it seq the array element, but not doing the same to GCC. even with -O0, gcc gets rid of the loop body. one solution: add in the assembly to actually read the array (i'm too lazy and busy to do this). - hal -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume > -----Original Message----- > From: haskell-cafe-admin@haskell.org=20 > [mailto:haskell-cafe-admin@haskell.org] On Behalf Of Lex Stein > Sent: Thursday, June 26, 2003 3:46 PM > To: Sven Panne > Cc: haskell-cafe@haskell.org > Subject: Re: haskell array access >=20 >=20 >=20 > Great, thanks. Those suggestions narrow the gap from GHC -O being 330x > slower than GCC -O3 to it being 20x slower. Here are the new results: >=20 > gcc -O3 0.54s > ocamlopt 1.11s > ghc -O 10.76s > ocamlc 14.10s >=20 > GHC is still pretty slow for native x86 instruction code. Is=20 > there any way > to further explain the performance gap ? (new code below) >=20 > Thanks! > Lex >=20 > Haskell (GHC) source: >=20 > import Array > k :: Array Int Int > k =3D Array.array (0,15) [(i, i+1) | i <- [0 .. 15] ] > acc :: Int -> Int > acc 0 =3D 0 > acc n =3D seq (k Array.! (n `mod` 16)) (acc (n-1)) > main =3D do > print (acc 100000000) >=20 > Caml test source: >=20 > let a =3D Array.make 16 0;; > let rec do1 i z =3D > if (i>100000000) then z else > do1 (i+1) (z + a.(i mod 16));; > do1 0 0;; >=20 > C (gcc) test source: >=20 > int main () { > int i, k =3D 0; > int a [16]; > for (i=3D0; i<100000000; i++) { > k +=3D a [i % 16]; > } > return (k); > } >=20 >=20 > On Fri, 27 Jun 2003, Sven Panne wrote: >=20 > > Well, part of the answer is definitely that the Haskell=20 > program is the > > *only* one which really uses the array elements. :-) I=20 > guess that the > > compilers for the other languages simply remove the array=20 > access from > > the generated code (gcc definitely does, only an empty loop=20 > remains). > > > > Another reason is that the type signatures are missing, so=20 > Integer is > > used instead of Int, which is a bit unfair. Adding > > > > k :: Array Int Int > > acc :: Int -> Int > > > > cuts down the time by more than factor 5 on my machine. > > > > Cheers, > > S. > > > > > > _______________________________________________ > > Haskell-Cafe mailing list > > Haskell-Cafe@haskell.org > > http://www.haskell.org/mailman/listinfo/haskell-cafe > > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe >=20 From stein@eecs.harvard.edu Fri Jun 27 00:11:44 2003 From: stein@eecs.harvard.edu (Lex Stein) Date: Thu, 26 Jun 2003 19:11:44 -0400 (EDT) Subject: haskell array access In-Reply-To: <935F630FDD8A7F4CB1A0412C7CA4371405ED06F0@RED-MSG-10.redmond.corp.microsoft.com> References: <935F630FDD8A7F4CB1A0412C7CA4371405ED06F0@RED-MSG-10.redmond.corp.microsoft.com> Message-ID: You must be using my old example, with gcc -O3 my new example does access the array and is 20x faster than the ghc -O code. Scroll down for "-->" that I inserted beside the instruction to see the array access. .file "arrayloop.c" .version "01.01" gcc2_compiled.: .text .p2align 2,0x90 .globl main .type main,@function main: pushl %ebp movl %esp,%ebp subl $80,%esp pushl %esi pushl %ebx xorl %ebx,%ebx xorl %ecx,%ecx leal -64(%ebp),%esi .p2align 2,0x90 .L6: movl %ecx,%edx testl %ecx,%ecx jge .L7 leal 15(%ecx),%edx .L7: andl $-16,%edx movl %ecx,%eax subl %edx,%eax --> addl (%esi,%eax,4),%ebx incl %ecx cmpl $99999999,%ecx jle .L6 movl %ebx,%eax popl %ebx popl %esi leave ret .Lfe1: .size main,.Lfe1-main .ident "GCC: (GNU) c 2.95.4 20020320 [FreeBSD]" On Thu, 26 Jun 2003, Hal Daume wrote: > This has been hinted to before: gcc gets rid of the loop. > > bash-2.05b$ gcc -O3 arr.c -S -o arr.s > bash-2.05b$ cat arr.s > .file "arr.c" > .def ___main; .scl 2; .type 32; .endef > .text > .align 2 > .align 16 > .globl _main > .def _main; .scl 2; .type 32; .endef > _main: > pushl %ebp > movl %esp, %ebp > subl $72, %esp > xorl %eax, %eax > andl $-16, %esp > call __alloca > call ___main > xorl %eax, %eax > .align 16 > L7: > incl %eax > cmpl $100000000, %eax > jle L7 > leave > ret > > the inside of the loop is exactly: > > L7: > incl %eax > cmpl $100000000, %eax > jle L7 > > which doesn't read the array! essentially you are being unfare to ghc > by making it seq the array element, but not doing the same to GCC. even > with -O0, gcc gets rid of the loop body. > > one solution: add in the assembly to actually read the array (i'm too > lazy and busy to do this). > > - hal > > > -- > Hal Daume III | hdaume@isi.edu > "Arrest this man, he talks in maths." | www.isi.edu/~hdaume > > > > -----Original Message----- > > From: haskell-cafe-admin@haskell.org > > [mailto:haskell-cafe-admin@haskell.org] On Behalf Of Lex Stein > > Sent: Thursday, June 26, 2003 3:46 PM > > To: Sven Panne > > Cc: haskell-cafe@haskell.org > > Subject: Re: haskell array access > > > > > > > > Great, thanks. Those suggestions narrow the gap from GHC -O being 330x > > slower than GCC -O3 to it being 20x slower. Here are the new results: > > > > gcc -O3 0.54s > > ocamlopt 1.11s > > ghc -O 10.76s > > ocamlc 14.10s > > > > GHC is still pretty slow for native x86 instruction code. Is > > there any way > > to further explain the performance gap ? (new code below) > > > > Thanks! > > Lex > > > > Haskell (GHC) source: > > > > import Array > > k :: Array Int Int > > k = Array.array (0,15) [(i, i+1) | i <- [0 .. 15] ] > > acc :: Int -> Int > > acc 0 = 0 > > acc n = seq (k Array.! (n `mod` 16)) (acc (n-1)) > > main = do > > print (acc 100000000) > > > > Caml test source: > > > > let a = Array.make 16 0;; > > let rec do1 i z = > > if (i>100000000) then z else > > do1 (i+1) (z + a.(i mod 16));; > > do1 0 0;; > > > > C (gcc) test source: > > > > int main () { > > int i, k = 0; > > int a [16]; > > for (i=0; i<100000000; i++) { > > k += a [i % 16]; > > } > > return (k); > > } > > > > > > On Fri, 27 Jun 2003, Sven Panne wrote: > > > > > Well, part of the answer is definitely that the Haskell > > program is the > > > *only* one which really uses the array elements. :-) I > > guess that the > > > compilers for the other languages simply remove the array > > access from > > > the generated code (gcc definitely does, only an empty loop > > remains). > > > > > > Another reason is that the type signatures are missing, so > > Integer is > > > used instead of Int, which is a bit unfair. Adding > > > > > > k :: Array Int Int > > > acc :: Int -> Int > > > > > > cuts down the time by more than factor 5 on my machine. > > > > > > Cheers, > > > S. > > > > > > > > > _______________________________________________ > > > Haskell-Cafe mailing list > > > Haskell-Cafe@haskell.org > > > http://www.haskell.org/mailman/listinfo/haskell-cafe > > > > > _______________________________________________ > > Haskell-Cafe mailing list > > Haskell-Cafe@haskell.org > > http://www.haskell.org/mailman/listinfo/haskell-cafe > > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe > From stein@eecs.harvard.edu Fri Jun 27 00:14:39 2003 From: stein@eecs.harvard.edu (Lex Stein) Date: Thu, 26 Jun 2003 19:14:39 -0400 (EDT) Subject: haskell array access In-Reply-To: References: <935F630FDD8A7F4CB1A0412C7CA4371405ED06F0@RED-MSG-10.redmond.corp.microsoft.com> Message-ID: Actually, to be completely correct, the access is the movl 2 instructions above the "-->". The "-->" points to the accumulation in the local variable k. Any ideas how I can further narrow this 20x gap and improve GHC's observed relative array access performance ? int main () { int i, k = 0; int a [16]; for (i=0; i<100000000; i++) { k += a [i % 16]; } return k; } Thanks! Lex -- Lex Stein http://www.eecs.harvard.edu/~stein/ stein@eecs.harvard.edu TEL: 617-233-0246 On Thu, 26 Jun 2003, Lex Stein wrote: > > You must be using my old example, with gcc -O3 my new example does access > the array and is 20x faster than the ghc -O code. Scroll down for > "-->" that I inserted beside the instruction to see the array access. > > .file "arrayloop.c" > .version "01.01" > gcc2_compiled.: > .text > .p2align 2,0x90 > .globl main > .type main,@function > main: > pushl %ebp > movl %esp,%ebp > subl $80,%esp > pushl %esi > pushl %ebx > xorl %ebx,%ebx > xorl %ecx,%ecx > leal -64(%ebp),%esi > .p2align 2,0x90 > .L6: > movl %ecx,%edx > testl %ecx,%ecx > jge .L7 > leal 15(%ecx),%edx > .L7: > andl $-16,%edx > movl %ecx,%eax > subl %edx,%eax > --> addl (%esi,%eax,4),%ebx > incl %ecx > cmpl $99999999,%ecx > jle .L6 > movl %ebx,%eax > popl %ebx > popl %esi > leave > ret > .Lfe1: > .size main,.Lfe1-main > .ident "GCC: (GNU) c 2.95.4 20020320 [FreeBSD]" > > On Thu, 26 Jun 2003, Hal Daume wrote: > > > This has been hinted to before: gcc gets rid of the loop. > > > > bash-2.05b$ gcc -O3 arr.c -S -o arr.s > > bash-2.05b$ cat arr.s > > .file "arr.c" > > .def ___main; .scl 2; .type 32; .endef > > .text > > .align 2 > > .align 16 > > .globl _main > > .def _main; .scl 2; .type 32; .endef > > _main: > > pushl %ebp > > movl %esp, %ebp > > subl $72, %esp > > xorl %eax, %eax > > andl $-16, %esp > > call __alloca > > call ___main > > xorl %eax, %eax > > .align 16 > > L7: > > incl %eax > > cmpl $100000000, %eax > > jle L7 > > leave > > ret > > > > the inside of the loop is exactly: > > > > L7: > > incl %eax > > cmpl $100000000, %eax > > jle L7 > > > > which doesn't read the array! essentially you are being unfare to ghc > > by making it seq the array element, but not doing the same to GCC. even > > with -O0, gcc gets rid of the loop body. > > > > one solution: add in the assembly to actually read the array (i'm too > > lazy and busy to do this). > > > > - hal > > > > > > -- > > Hal Daume III | hdaume@isi.edu > > "Arrest this man, he talks in maths." | www.isi.edu/~hdaume > > > > > > > -----Original Message----- > > > From: haskell-cafe-admin@haskell.org > > > [mailto:haskell-cafe-admin@haskell.org] On Behalf Of Lex Stein > > > Sent: Thursday, June 26, 2003 3:46 PM > > > To: Sven Panne > > > Cc: haskell-cafe@haskell.org > > > Subject: Re: haskell array access > > > > > > > > > > > > Great, thanks. Those suggestions narrow the gap from GHC -O being 330x > > > slower than GCC -O3 to it being 20x slower. Here are the new results: > > > > > > gcc -O3 0.54s > > > ocamlopt 1.11s > > > ghc -O 10.76s > > > ocamlc 14.10s > > > > > > GHC is still pretty slow for native x86 instruction code. Is > > > there any way > > > to further explain the performance gap ? (new code below) > > > > > > Thanks! > > > Lex > > > > > > Haskell (GHC) source: > > > > > > import Array > > > k :: Array Int Int > > > k = Array.array (0,15) [(i, i+1) | i <- [0 .. 15] ] > > > acc :: Int -> Int > > > acc 0 = 0 > > > acc n = seq (k Array.! (n `mod` 16)) (acc (n-1)) > > > main = do > > > print (acc 100000000) > > > > > > Caml test source: > > > > > > let a = Array.make 16 0;; > > > let rec do1 i z = > > > if (i>100000000) then z else > > > do1 (i+1) (z + a.(i mod 16));; > > > do1 0 0;; > > > > > > C (gcc) test source: > > > > > > int main () { > > > int i, k = 0; > > > int a [16]; > > > for (i=0; i<100000000; i++) { > > > k += a [i % 16]; > > > } > > > return (k); > > > } > > > > > > > > > On Fri, 27 Jun 2003, Sven Panne wrote: > > > > > > > Well, part of the answer is definitely that the Haskell > > > program is the > > > > *only* one which really uses the array elements. :-) I > > > guess that the > > > > compilers for the other languages simply remove the array > > > access from > > > > the generated code (gcc definitely does, only an empty loop > > > remains). > > > > > > > > Another reason is that the type signatures are missing, so > > > Integer is > > > > used instead of Int, which is a bit unfair. Adding > > > > > > > > k :: Array Int Int > > > > acc :: Int -> Int > > > > > > > > cuts down the time by more than factor 5 on my machine. > > > > > > > > Cheers, > > > > S. > > > > > > > > > > > > _______________________________________________ > > > > Haskell-Cafe mailing list > > > > Haskell-Cafe@haskell.org > > > > http://www.haskell.org/mailman/listinfo/haskell-cafe > > > > > > > _______________________________________________ > > > Haskell-Cafe mailing list > > > Haskell-Cafe@haskell.org > > > http://www.haskell.org/mailman/listinfo/haskell-cafe > > > > > _______________________________________________ > > Haskell-Cafe mailing list > > Haskell-Cafe@haskell.org > > http://www.haskell.org/mailman/listinfo/haskell-cafe > > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe > From ddarius@hotpop.com Fri Jun 27 00:46:45 2003 From: ddarius@hotpop.com (Derek Elkins) Date: Thu, 26 Jun 2003 19:46:45 -0400 Subject: haskell array access In-Reply-To: References: <935F630FDD8A7F4CB1A0412C7CA4371405ED06ED@RED-MSG-10.redmond.corp.microsoft.com> Message-ID: <20030626194645.00004d0d.ddarius@hotpop.com> On Thu, 26 Jun 2003 17:48:17 -0400 (EDT) Lex Stein wrote: > > Hi, I'm measuring Haskell, Ocaml, and C, small array access > performance and the results with Haskell (GHC 5.02.2) are so bad that > I think I must be doing something wrong. Indeed, I am hardly a > seasoned Haskell programmer. My results are: > > ghc -O 61.60s > gcc -O3 0.20s > Ocamlopt 1.11s (tail call) > Ocamlopt 0.82s (for loop) > > Why is the ghc generated code so slow? The source for all the tests is > below. Any insight will be greatly appreciated (I'm running on Debian > Linux w/ 1GHz x86 CPU and 768MB RAM). > > The test cycles through an array of 16 elements, reading 100*10^6 > elements. > > Thanks! > Lex > > Haskell (ghc5) test source: > > import Array > k = Array.array (0,15) [(i, i+1) | i <- [0 .. 15] ] > acc 0 = 0 > acc n = seq (k Array.! (n `mod` 16)) (acc (n-1)) > main = do > print (acc 100000000) > > C (gcc) test source: > > int main () { > int i, k; > int a [16]; > for (i=0; i<=100000000; i++) { > k = a [i % 16]; > } > } well, to begin with, it's obviously already biased toward C. The C version doesn't initialize the array and doesn't display any output. Using MinGW gcc 3.2 I, like Sven, get a .S file that's just an empty loop(why the loop was even kept...?). Before you make a benchmark like this you may want to look at at least the basic parts of the following, which has Sven's advice among (many) other things. http://haskell.cs.yale.edu/ghc/docs/latest/html/users_guide/faster.html Anyways, int main(void){ int i, k; int a [16]; for (i=0; i<=100000000; i++) { k = a [i % 16]; } printf("%d\n",k); return 0; } compiled with MinGW 3.2 -O/-O2/-O3 runs in 1.8s using time. int main(void){ int i, k; int a [16]; for (i=0; i<=100000000; i++) { k = a [i % 16]; } printf("%d\n",k); return 0; } The following (compiled with -O2 -fglasgow-exts and GHC 6.1 i.e. a CVS version) beats the C version taking only .8s. They don't do the same thing (the Haskell version "does" more, but prints something different). Looking at the core/stg/c/asm (the asm and C was quite messy compared with other times), it certainly doesn't appear to be optimizing this to print 0, and it does appear (though I'm less sure here) to be doing everything as it should, but it's really hard to read the assembly, since we don't use the value we lookup I can easily see gcc dropping it altogether, though the C GHC spits out is pretty unusual for gcc, so it may not. module Main (main) where import Data.Array.Unboxed (UArray, array) import Data.Array.Base (unsafeAt) -- if C doesn't, why should we? import GHC.Exts k :: UArray Int Int k = array (0,15) [(i, i+1) | i <- [0 .. 15] ] acc :: Int# -> Int# acc 0# = 0# acc n = (k `unsafeAt` (I# (n `remInt#` 16#))) `seq` acc (n -# 1#) main :: IO () main = print (I# (acc 100000000#)) However, I'm am somewhat surprised that I seemingly had to unbox by hand to get quite close (in fact, better) than C. I expected the following version to be comparable to the C version (and it is orders of magnitude faster than the original version which was over 5min when I killed it (though I think I compiled it with just -O), this version taking 14s). module Main (main) where import Data.Array.Unboxed (UArray, array) import Data.Array.Base (unsafeAt) -- if C doesn't, why should we? k :: UArray Int Int k = array (0,15) [(i, i+1) | i <- [0 .. 15] ] acc :: Int -> Int acc 0 = 0 acc n = (k `unsafeAt` (n `mod` 16)) `seq` acc (n - 1) main :: IO () main = print (acc 100000000) From simonpj@microsoft.com Fri Jun 27 09:36:36 2003 From: simonpj@microsoft.com (Simon Peyton-Jones) Date: Fri, 27 Jun 2003 09:36:36 +0100 Subject: haskell array access Message-ID: <4B93206CA3C55D4F96A61C9B1DC80DE308D9FD@EUR-MSG-03.europe.corp.microsoft.com> Several comments 1. In Haskell "mod" is a lot more expensive than "rem", because it involves careful jiggery pokery with the sign of the result. That's why your boxed version was slower (nothing to do with boxing). 2. GHC does indeed optimise away the array access if you aren't careful, and does in Derek's code. Below is a version that avoids doing so, in the same way as the C version, by returning one of the values. 3. Derek correctly points out that gcc does not do array-bound checks. GHC should eliminate them, but it's a non-trivial analysis and GHC does not currently attempt it. You can always use unsafeAt, as Derek does. 4. The UArray stuff builds an array of unboxed Ints, like C. If you use ordinary boxed arrays, the loop has to unbox the Int every time around the loop, which makes it slower (2.6s) With that done, we get ghc -O2 -fliberate-case-threshold20 1.8s gcc -O2 1.4s Seems close enough to me; have not investigated further. The "liberate-case" thing is a practically-undocumented GHC optimisation that switches on with -O2. It specialises a loop that unboxes a free variable (here the array k) so that the unboxing doesn't happen each time round the loop. The threshold at which GHC thinks there is too much code dup is set very low by default, so the flag increases it. Simon =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D k :: UArray Int Int k =3D array (0,15) [(i, i+1) | i <- [0 .. 15] ] acc :: Int -> Int -> Int acc r 0 =3D r acc r n =3D r `seq` acc (k `unsafeAt` (n `rem` 16)) (n - 1) main :: IO () main =3D print (acc 0 100000000) =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D | Anyways, | int main(void){ | int i, k; | int a [16]; | for (i=3D0; i<=3D100000000; i++) { | k =3D a [i % 16]; | } | printf("%d\n",k); | return 0; | } | compiled with MinGW 3.2 -O/-O2/-O3 runs in 1.8s using time. |=20 | int main(void){ | int i, k; | int a [16]; | for (i=3D0; i<=3D100000000; i++) { | k =3D a [i % 16]; | } | printf("%d\n",k); | return 0; | } |=20 | The following (compiled with -O2 -fglasgow-exts and GHC 6.1 i.e. a CVS | version) beats the C version taking only .8s. They don't do the same | thing (the Haskell version "does" more, but prints something different). | Looking at the core/stg/c/asm (the asm and C was quite messy compared | with other times), it certainly doesn't appear to be optimizing this to | print 0, and it does appear (though I'm less sure here) to be doing | everything as it should, but it's really hard to read the assembly, | since we don't use the value we lookup I can easily see gcc dropping it | altogether, though the C GHC spits out is pretty unusual for gcc, so it | may not. |=20 | module Main (main) where | import Data.Array.Unboxed (UArray, array) | import Data.Array.Base (unsafeAt) -- if C doesn't, why should we? | import GHC.Exts |=20 | k :: UArray Int Int | k =3D array (0,15) [(i, i+1) | i <- [0 .. 15] ] |=20 | acc :: Int# -> Int# | acc 0# =3D 0# | acc n =3D (k `unsafeAt` (I# (n `remInt#` 16#))) `seq` acc (n -# 1#) |=20 | main :: IO () | main =3D print (I# (acc 100000000#)) |=20 | However, I'm am somewhat surprised that I seemingly had to unbox by hand | to get quite close (in fact, better) than C. I expected the following | version to be comparable to the C version (and it is orders of magnitude | faster than the original version which was over 5min when I killed it | (though I think I compiled it with just -O), this version taking 14s). |=20 | module Main (main) where | import Data.Array.Unboxed (UArray, array) | import Data.Array.Base (unsafeAt) -- if C doesn't, why should we? |=20 | k :: UArray Int Int | k =3D array (0,15) [(i, i+1) | i <- [0 .. 15] ] |=20 | acc :: Int -> Int | acc 0 =3D 0 | acc n =3D (k `unsafeAt` (n `mod` 16)) `seq` acc (n - 1) |=20 | main :: IO () | main =3D print (acc 100000000) |=20 | _______________________________________________ | Haskell-Cafe mailing list | Haskell-Cafe@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-cafe From ddarius@hotpop.com Fri Jun 27 11:00:29 2003 From: ddarius@hotpop.com (Derek Elkins) Date: Fri, 27 Jun 2003 06:00:29 -0400 Subject: haskell array access In-Reply-To: <4B93206CA3C55D4F96A61C9B1DC80DE308D9FD@EUR-MSG-03.europe.corp.microsoft.com> References: <4B93206CA3C55D4F96A61C9B1DC80DE308D9FD@EUR-MSG-03.europe.corp.microsoft.com> Message-ID: <20030627060029.0000745d.ddarius@hotpop.com> On Fri, 27 Jun 2003 09:36:36 +0100 "Simon Peyton-Jones" wrote: > Several comments > > 1. In Haskell "mod" is a lot more expensive than "rem", because it > involves careful jiggery pokery with the sign of the result. That's > why your boxed version was slower (nothing to do with boxing). Ah. I guess I should've checked the core closer (or more than a quick glimpse) before making wild assumptions. The (relatively) few other times I've unboxed by hand, I've found GHC had already done it. I did think mod might have been a problem, but I didn't expect it to be -that- much of a difference, hence assuming it was boxing related (I didn't see a modInt# so I figured remInt# was more or less it, it didn't know how much less). > 2. GHC does indeed optimise away the array access if you aren't > careful, and does in Derek's code. Below is a version that avoids > doing so, in the same way as the C version, by returning one of the > values. Yeah, I was having a very hard time believing it, as the code was comparable to gcc optimising out the array access (which took ~.6 seconds on my computer). > 3. Derek correctly points out that gcc does not do array-bound > checks. GHC should eliminate them, but it's a non-trivial analysis and > GHC does not currently attempt it. You can always use unsafeAt, as > Derek does. I was thinking that that would be nice, but was not surprised that it wasn't there. Are there any concoctions of flags/pragmas/techniques to coax GHC into unrolling a function (or rather an IO computation in this case) a couple of iterations. There was another (admittedly also noddy) program that I could get to near gcc, but only by unrolling by hand (though Ian's TH stuff likely could have done it). From maeder@tzi.de Fri Jun 27 11:55:48 2003 From: maeder@tzi.de (Christian Maeder) Date: Fri, 27 Jun 2003 12:55:48 +0200 Subject: Simple monads In-Reply-To: <20030626175743.00001bf5.ddarius@hotpop.com> References: <20030626175743.00001bf5.ddarius@hotpop.com> Message-ID: <3EFC22B4.4010405@tzi.de> >>not deeply >>understanding the use of Haskell extensions in the State source, > > > I'm assuming Control.Monad.State's source in which case -no- extensions > are used for -State- (well, at least I don't see any quickly glancing). > Extensions are used for the -MonadState class-. The portable parts of Control.Monad.State (that are sufficient for most cases) should be in an extra module (maybe called Control.Monad.StateTypes). In addition further non-overloaded names for put, get, gets and modify would be needed (maybe putState, getState, etc.) There's no point to write your own "instance Monad ..." just because you want (or have) to be Haskell98 compliant. The previous "newtype Labeller a = Labeller (Int -> (Int, a))" (the result tuple is reversed within Control.Monad.State) would simply become (untested): newtype Labeller a = State Int a newLabel = do { n <- get; put (n + 1); return (Label n) } runLabeller l = execState l minBound Christian From maeder@tzi.de Fri Jun 27 12:49:29 2003 From: maeder@tzi.de (Christian Maeder) Date: Fri, 27 Jun 2003 13:49:29 +0200 Subject: Simple monads In-Reply-To: <3EFC22B4.4010405@tzi.de> References: <20030626175743.00001bf5.ddarius@hotpop.com> <3EFC22B4.4010405@tzi.de> Message-ID: <3EFC2F49.6090705@tzi.de> > The previous "newtype Labeller a = Labeller (Int -> (Int, a))" (the > result tuple is reversed within Control.Monad.State) would simply become > (untested): > > newtype Labeller a = State Int a > > newLabel = do { n <- get; put (n + 1); return (Label n) } > > runLabeller l = execState l minBound it must be "evalState" instead of "execState" From edwin@chinaconferences.net Fri Jun 27 14:09:20 2003 From: edwin@chinaconferences.net (Edwin Jones) Date: Fri, 27 Jun 2003 13:09:20 -0000 Subject: ELearnChina Conference 2003 - Only 4 Weeks To Go! Message-ID: <20030627121656.52495421EFA@www.haskell.org> Hey its me again! Ok, there are still a few places left at the best Elearning Event of the year. Please contact me directly for final discounted prices [yes, even lower now] Yours, Edwin Jones www.chinaconferences.net Sales China Conferences Tel +44 131 440 9881 Fax +44 131 440 9882 edwin@chinaconferences.net From mark@felinemail.zzn.com Fri Jun 27 15:52:51 2003 From: mark@felinemail.zzn.com (Mark Espinoza) Date: Fri, 27 Jun 2003 09:52:51 -0500 Subject: Help with ghci and Yet Another Haskell Tutorial Message-ID: <5654DCBA8E7FE644ABB4A42C67BE0A10@mark.felinemail.zzn.com>

Greetings,

I am going through the Tutorial using ghc on a redhat 8.0 system.
Everything works fine untill I get to the map function:

Prelude>  map toUpper "hello world"

<interactive>:1: Variable not in scope: `toUpper'
Prelude>

Can anyone tel me what is or might be going on?

Thanks.

Sincerely,

Mark



Get your free e-mail address at http://felinemail.zzn.com
___________________________________________________________
Get your own Web-based E-mail Service at http://www.zzn.com

From t-hald@microsoft.com Fri Jun 27 16:17:05 2003 From: t-hald@microsoft.com (Hal Daume) Date: Fri, 27 Jun 2003 08:17:05 -0700 Subject: Help with ghci and Yet Another Haskell Tutorial Message-ID: <935F630FDD8A7F4CB1A0412C7CA4371405ED06F2@RED-MSG-10.redmond.corp.microsoft.com> toUpper is in the Char (or Data.Char) library. You can do: Prelude> :m Data.Char Data.Char> map toUpper "hello world" or specify it completely. Prelude> map Data.Char.toUpper "hello world" I'll fix this reference in YAHT. I believe that Hugs automatically exports toUpper, which is why it was in there to begin with. - Hal -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume -----Original Message----- From: haskell-cafe-admin@haskell.org [mailto:haskell-cafe-admin@haskell.org] On Behalf Of Mark Espinoza Sent: Friday, June 27, 2003 7:53 AM To: haskell-cafe@haskell.org Subject: Help with ghci and Yet Another Haskell Tutorial Greetings, I am going through the Tutorial using ghc on a redhat 8.0 system. Everything works fine untill I get to the map function: Prelude> map toUpper "hello world" :1: Variable not in scope: `toUpper' Prelude> Can anyone tel me what is or might be going on? Thanks. Sincerely, Mark Get your free e-mail address at http://felinemail.zzn.com ___________________________________________________________ Get your own Web-based E-mail Service at http://www.zzn.com _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe=20 From wolfgang@jeltsch.net Fri Jun 27 17:07:49 2003 From: wolfgang@jeltsch.net (Wolfgang Jeltsch) Date: Fri, 27 Jun 2003 18:07:49 +0200 Subject: Simple monads In-Reply-To: <3EFC22B4.4010405@tzi.de> References: <20030626175743.00001bf5.ddarius@hotpop.com> <3EFC22B4.4010405@tzi.de> Message-ID: <200306271807.49983.wolfgang@jeltsch.net> On Friday, 2003-06-27, 12:55, CEST, Christian Maeder wrote: > [...] > The portable parts of Control.Monad.State (that are sufficient for most > cases) should be in an extra module (maybe called Control.Monad.StateTypes). > In addition further non-overloaded names for put, get, gets and modify would > be needed (maybe putState, getState, etc.) Hello, I fear, this would complicate the module structure too much. And it will become unnecessary because some time (in the near future?) multi-parameter classes with functional dependencies will be a standardized feature which is supported by all major Haskell implementations. I hope, at least. ;-) > [...] Wolfgang From Shawn@Garbett.org Fri Jun 27 18:10:55 2003 From: Shawn@Garbett.org (Shawn P. Garbett) Date: Fri, 27 Jun 2003 12:10:55 -0500 Subject: haskell array access In-Reply-To: References: <935F630FDD8A7F4CB1A0412C7CA4371405ED06ED@RED-MSG-10.redmond.corp.microsoft.com> <3EFB6E9F.8040709@informatik.uni-muenchen.de> Message-ID: <200306271210.57855.Shawn@Garbett.org> =2D----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Thursday 26 June 2003 05:46 pm, Lex Stein wrote: > Great, thanks. Those suggestions narrow the gap from GHC -O being 330x > slower than GCC -O3 to it being 20x slower. Here are the new results: > > gcc -O3 0.54s > ocamlopt 1.11s > ghc -O 10.76s > ocamlc 14.10s > > GHC is still pretty slow for native x86 instruction code. Is there any way > to further explain the performance gap ? (new code below) I redid both programs to make them equivalent in action. The haskell progra= m=20 was not actually summing the results, the C program was not checking array= =20 bounds (Haskell does), the C program did not initialize the array and the C= =20 program didn't print the result. Times on my laptop (Crusoe 933): 62.061s : Haskell (Array -O2) Note: lot's 'o disk grinding! 18.231s : Haskell (UArray -O2) 18.108s : Haskell (UArray -O2 -fvia-c) 17.443s : Haskell (UArray -O2 -funfolding-update-in-place) 0.807s : C (-O3 without bound check) 1.127s : C (-O3 with bound check) At best case for Haskell, 15.5 times slower. The thing about bounds checkin= g,=20 in Haskell it's always there. In C, you might have it, you might not there = is=20 no certainty by the language, only by design and implementation. So with C,= =20 one is free to live dangerously. I changed the "mod" value to 17, so that out of bound access takes place in= =20 the Haskell program. It gives me the following: =46ail: Ix{Int}.index: Index (16) out of range ((0,15)) I did the same to the C program (without the bounds checking), it spits out= a=20 value and give no indication that anything improper was done. =2D --------------------------------------------- Haskell Original (redone to be funtionally equivalent) =2D ---------------------------------------------- import Array a :: Array Int Int a =3D array (0,15) [(i, i) | i <- [0 .. 15] ] acc :: Int -> Int -> Int acc s 0 =3D s acc s n =3D acc (s + (a ! (n `mod` 16))) (n-1) main :: IO () main =3D do print $ acc 0 100000000 =2D ----------------------------------------------------- C Version with some modifications as well =2D ---------------------------------------------------------- #include int main () { int i; int k; int idx;=20 int a[16]; for (i=3D0; i<16; ++i) { a[i] =3D i; } for (k=3D0, i=3D100000000; i>0; --i) { idx =3D i % 16; if((idx > 15) || (idx < 0)) { fprintf(stderr, "Out of range access (0,15) value is %d\n", idx); exit(1); } =20 k +=3D a [idx];=20 } printf("%d\n", k); } =2D -------------------------------------- New Haskell version with Unboxed Array Note:it was a simple change of import and type =2D ----------------------------------------- import Data.Array.Unboxed a :: UArray Int Int a =3D array (0,15) [(i, i) | i <- [0 .. 15] ] acc :: Int -> Int -> Int acc s 0 =3D s acc s n =3D acc (s + (a ! (n `mod` 16))) (n-1) main :: IO () main =3D do print $ acc 0 100000000 =2D----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.1 (GNU/Linux) iEYEARECAAYFAj78eqEACgkQDtpPjAQxZ6AgPQCePRrgaAmxMzfW7d2akvaXLJU7 SxAAnj7wO7vx6zXQwRVBXpMrbqw2wZDF =3DoMhR =2D----END PGP SIGNATURE----- From wolfgang@jeltsch.net Fri Jun 27 18:27:36 2003 From: wolfgang@jeltsch.net (Wolfgang Jeltsch) Date: Fri, 27 Jun 2003 19:27:36 +0200 Subject: Simple monads In-Reply-To: <20030626175743.00001bf5.ddarius@hotpop.com> References: <20030626175743.00001bf5.ddarius@hotpop.com> Message-ID: <200306271927.36405.wolfgang@jeltsch.net> On Thursday, 2003-06-26, 23:57, CEST, Derek Elkins wrote: > [...] > > not deeply understanding the use of Haskell extensions in the State > > source, > > I'm assuming Control.Monad.State's source in which case -no- extensions a= re > used for -State- (well, at least I don't see any quickly glancing). > Extensions are used for the -MonadState class-. For the MonadState class > they are pretty much necessary. Multiparameter type classes are necessary > because the state type depends on the monad (get would have type forall > s.Monad m =3D> m -> s otherwise which is rather meaningless), the function > dependencies tell the type checker that the state type is completely > determined by the monad type. Hello, why not swap the state and the monad parameter of StateT? The definition wo= uld=20 become something like the following: newtype StateT m s a =3D StateT (s -> m (a,s)) With this we could create a MonadState class which doesn't use type system= =20 extensions. It could be defined like this: class MonadState m where get :: m s s put :: s -> m s () Note that m now has kind * -> * -> *. Note also that this restricts the=20 MonadState class because only state transformers which can work with every= =20 state type are now possible as instances. But, at least, State and our=20 modified StateT can be instantiated without problem. The problem arises when we try to make a MonadTrans instance for our new=20 StateT because MonadTrans needs a type of kind * -> * -> * whoose first=20 argument is a monad. But we can create a different MonadTrans class based o= n=20 the kind of functional dependency usage we just dropped for MonadState. We= =20 just write: class MonadTrans (Monad m, Monad tm) =3D> m tm | tm -> m where lift :: m a -> tm a Instead of writing instance MonadTrans T where ... we would now write instance Monad m =3D> MonadTrans m (T m) where ... and for our new StateT type we would write instance Monad m =3D> MonadTrans m (StateT m s) where ... The new MonadTrans class would be more powerful. This would have the nice=20 effect that we don't need MonadIO anymore. Instead of writing MonadIO m we could just use MonadTrans IO m Changing MonadTrans this way would help me with my parser module.=B9 I have= a=20 type Parser which needs three parameters, a "base monad", a token type and = an=20 output type. The base monad parameter has the same purpose as the monad=20 parameter in ReaderT, WriterT, StateT etc. The lift function makes sense fo= r=20 my parser type, so I want a MonadTrans instance. This would restrict me to= =20 the parameter order token - base monad - output which is rather unfortunate for me. The reason is that there are parser=20 functions which fulfill the arrow axioms. The arrow type is a parser applie= d=20 to a specific base monad. So I want to write something like instance Monad baseMonad =3D> Arrow (Parser baseMonad) where ... which implies that the base monad must be the first parameter. This brings me to another point. One year ago we had a discussion on The=20 Haskell Mailing List concerning arrows. (The subject of the mails was just= =20 "arrows".) The point was that it seemed strange to me that first and second= =20 are included in the basic arrow class Arrow while left and right have their= =20 extra class ArrowChoice. Not only that it seemed strange to me but it made = it=20 impossible to make Parser baseMonad an instance of Arrow. Parser baseMonad= =20 has nice implementations of pure and (>>>) but none of first or second. Currently, I use my own Arrow module which provides an arrow class, that=20 doesn't include first and second. I'm really not happy with using a=20 replacement for a module from the hierarchical libraries. Is there any chan= ce=20 of changing the class structure of Control.Arrow? > [...] Wolfgang =B9 The parser module is part of Seaweed. It's the module Seaweed.Core.Pars= ing.=20 The source code of Seaweed can be accessed via this URI: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/seaweed/code/ There is also the module Seaweed.Core.Parsing.Utilities which provides seve= ral=20 useful things implemented on top of the core parsing module. From t-hald@microsoft.com Fri Jun 27 18:30:09 2003 From: t-hald@microsoft.com (Hal Daume) Date: Fri, 27 Jun 2003 10:30:09 -0700 Subject: haskell array access Message-ID: <935F630FDD8A7F4CB1A0412C7CA4371405ED06F3@RED-MSG-10.redmond.corp.microsoft.com> > At best case for Haskell, 15.5 times slower. The thing about=20 > bounds checking,=20 > in Haskell it's always there. In C, you might have it, you=20 > might not there is=20 > no certainty by the language, only by design and=20 > implementation. So with C,=20 > one is free to live dangerously. If you're using GHC, there's Data.Array.Base.unsafeAt which is the one which doesn't do bounds checking. From droundy@jdj5.mit.edu Fri Jun 27 18:49:03 2003 From: droundy@jdj5.mit.edu (David Roundy) Date: Fri, 27 Jun 2003 13:49:03 -0400 Subject: haskell array access In-Reply-To: <200306271210.57855.Shawn@Garbett.org> References: <935F630FDD8A7F4CB1A0412C7CA4371405ED06ED@RED-MSG-10.redmond.corp.microsoft.com> <3EFB6E9F.8040709@informatik.uni-muenchen.de> <200306271210.57855.Shawn@Garbett.org> Message-ID: <20030627174903.GB7227@jdj5.mit.edu> On Fri, Jun 27, 2003 at 12:10:55PM -0500, Shawn P. Garbett wrote: > - -------------------------------------- > New Haskell version with Unboxed Array > Note:it was a simple change of import and type > - ----------------------------------------- > import Data.Array.Unboxed > > a :: UArray Int Int > a = array (0,15) [(i, i) | i <- [0 .. 15] ] > > acc :: Int -> Int -> Int > acc s 0 = s > acc s n = acc (s + (a ! (n `mod` 16))) (n-1) > > main :: IO () > main = do > print $ acc 0 100000000 I'd be curious to see timing on the following: import Data.Array.Unboxed import Data.Bits a :: UArray Int Int a = array (0,15) [(i, i) | i <- [0 .. 15] ] acc :: Int -> Int -> Int acc s 0 = s acc s n = acc (s + (a ! (n .&. 15))) (n-1) main :: IO () main = do print $ acc 0 100000000 All I've done eliminated the mod call in favor of a bitwise and. I would hope that the C compiler would do that, at least if it gives any improvement. -- David Roundy http://civet.berkeley.edu/droundy/ From GK@ninebynine.org Fri Jun 27 18:16:22 2003 From: GK@ninebynine.org (Graham Klyne) Date: Fri, 27 Jun 2003 18:16:22 +0100 Subject: Simple monads In-Reply-To: Message-ID: <5.1.0.14.2.20030627174405.0335f038@127.0.0.1> At a casual glance, your Labeller looks to me like a state transformer monad. I've found that the State transformer monad in the hierarchical libraries can be useful for this kind of thing; the following example is part of a larger program, so it can't be run in isolation, but I hope it shows some possibilities. Points to note: + the initial state is an empty list, part of the 'runState' call in 'rdfQuerySubs2' + fmapM is used to sequence the monad over a fairly complex data structure, based on a FunctorM class described in a message by Tomasz Zielonka sent to the Haskell mailing list on 4 June 2003. The signature of fmapM is: fmapM :: Monad m => (a -> m b) -> (t a -> m (t b)) where, in this case, instantiates as fmapM :: (RDFLabel -> State [RDFLabel] RDFLabel) -> (RDFGraph -> State [RDFLabel] RDFGraph) + 'mapNode' returns the monad instance that collects unbound variables. The key method is update which, as its name suggests, updates the state. + The library type State handles most of the coding detail for the monad itself, leaving the application code to focus on using it. [[ import Control.Monad.State ( State(..), modify ) ... -- This function applies a substitution for a single set of variable -- bindings, returning the result and a list of unbound variables. -- It uses a state transformer monad to collect the list of unbound -- variables. rdfQuerySubs2 :: RDFQueryBinding -> RDFGraph -> (RDFGraph,[RDFLabel]) rdfQuerySubs2 varb gr = runState ( fmapM (mapNode varb) gr ) [] -- Auxiliary monad function for rdfQuerySubs2. -- This returns a state transformer Monad which in turn returns the -- substituted node value based on the supplied query variable bindings. -- The monad state is a list of labels which accumulates all those -- variables seen for which no substitution was available. mapNode :: RDFQueryBinding -> RDFLabel -> State [RDFLabel] RDFLabel mapNode varb lab = case qbMap varb lab of Just v -> return v Nothing -> if isQueryVar lab then do { modify (addVar lab) ; return lab } else return lab ]] At 14:40 26/06/03 -0400, Mark Carroll wrote: >Not really seeing why Unique is in the IO monad, not deeply understanding >the use of Haskell extensions in the State source, and wanting to try to >learn a bit more about monads, I thought I'd try to write my own monad for >the first time: something for producing a series of unique labels. This is >how it turned out: > >========================================================================== >module Label (Label, Labeller, newLabel) >where >import Monad > >newtype Label = Label Int deriving (Eq, Ord) > >newtype Labeller a = Labeller (Int -> (Int, a)) > >instance Monad Labeller where > return r = Labeller (\n -> (n, r)) > (Labeller g) >>= y = > let f m = let (r, n) = g m > Labeller h = y n > in h r > in Labeller f > >newLabel :: Labeller Label > >newLabel = Labeller (\n -> (n + 1, Label n)) > >runLabeller :: Labeller a -> a > >runLabeller (Labeller l) = snd (l minBound) > >labelTest :: Labeller [Int] > >labelTest = > do Label a <- newLabel > Label b <- newLabel > Label c <- newLabel > Label d <- newLabel > return [a,b,c,d] > >main = print (runLabeller labelTest) >========================================================================== > >I was thinking that maybe, > >(a) People could point out to me where I'm still confused, as revealed by >my code. Is it needlessly complicated? > >(b) My code may be instructive to someone else. > >-- Mark > >_______________________________________________ >Haskell-Cafe mailing list >Haskell-Cafe@haskell.org >http://www.haskell.org/mailman/listinfo/haskell-cafe ------------------- Graham Klyne PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E From ashley@semantic.org Fri Jun 27 23:57:19 2003 From: ashley@semantic.org (Ashley Yakeley) Date: Fri, 27 Jun 2003 15:57:19 -0700 Subject: Template Haskell question Message-ID: Can anyone tell me what's wrong with this? -- ghc -fglasgow-exts -c TH.hs module TH where { import Language.Haskell.THSyntax; class HasZero a where { zero :: a; }; aninstance :: TypQ -> Q [Dec]; aninstance t = [d| instance HasZero $t where -- error here { zero = 0; }; |]; $(aninstance [t|Int|]) $(aninstance [t|Integer|]) } $ ghc -fglasgow-exts -c TH.hs TH.hs:14: Malformed context in instance header All I want to do is spin off a number instances for a number of types... -- Ashley Yakeley, Seattle WA From ashley@semantic.org Sat Jun 28 00:13:58 2003 From: ashley@semantic.org (Ashley Yakeley) Date: Fri, 27 Jun 2003 16:13:58 -0700 Subject: Arrow Classes References: <20030626175743.00001bf5.ddarius@hotpop.com> <200306271927.36405.wolfgang@jeltsch.net> Message-ID: In article <200306271927.36405.wolfgang@jeltsch.net>, Wolfgang Jeltsch wrote: > This brings me to another point. One year ago we had a discussion on The > Haskell Mailing List concerning arrows. (The subject of the mails was just > "arrows".) The point was that it seemed strange to me that first and second > are included in the basic arrow class Arrow while left and right have their > extra class ArrowChoice. Not only that it seemed strange to me but it made it > impossible to make Parser baseMonad an instance of Arrow. Parser baseMonad > has nice implementations of pure and (>>>) but none of first or second. I agree. My own Arrow module hierarchy looks more or less like this: class Compositor comp where identity :: comp a a compose :: comp b c -> comp a b -> comp a c class (Compositor arrow) => Arrow arrow where arrFunction :: (p -> q) -> arrow p q -- | corresponds to Hughes\' \'Arrow\' class (Arrow arrow) => ProductArrow arrow where arrApply :: arrow p (q -> r) -> arrow p q -> arrow p r arrProduct :: arrow p q -> arrow p r -> arrow p (q,r) arrProduct = liftA2 (,) class (Arrow arrow) => CoproductArrow arrow where arrCoproduct :: arrow p r -> arrow q r -> arrow (Either p q) r -- | corresponds to Hughes\' \'ArrowChoice\' class (ProductArrow arrow,CoproductArrow arrow) => FullArrow arrow instance (ProductArrow arrow,CoproductArrow arrow) => FullArrow arrow class (Arrow arrow) => ArrowFix arrow where arrFix :: arrow (p,q) q -> arrow p q class (FullArrow arrow) => ApplyArrow arrow where arrApplyArrow :: arrow (arrow p q,p) q Note the symmetry between ProductArrow and CoproductArrow. See for all the details. -- Ashley Yakeley, Seattle WA From igloo@earth.li Sat Jun 28 00:49:52 2003 From: igloo@earth.li (Ian Lynagh) Date: Sat, 28 Jun 2003 00:49:52 +0100 Subject: Template Haskell question In-Reply-To: References: Message-ID: <20030627234952.GA14641@orthogonal.chaos.earth.li> On Fri, Jun 27, 2003 at 03:57:19PM -0700, Ashley Yakeley wrote: > > aninstance :: TypQ -> Q [Dec]; > aninstance t = [d| > > instance HasZero $t where -- error here > { > zero = 0; > }; > > |]; You can only splice in expressions and declarations at the moment. Ian From jenglish@flightlab.com Sat Jun 28 17:00:55 2003 From: jenglish@flightlab.com (Joe English) Date: Sat, 28 Jun 2003 09:00:55 -0700 Subject: Arrow Classes In-Reply-To: References: <20030626175743.00001bf5.ddarius@hotpop.com> <200306271927.36405.wolfgang@jeltsch.net> Message-ID: <200306281600.h5SG0tN15486@dragon.flightlab.com> Ashley Yakeley wrote: > Wolfgang Jeltsch wrote: > > > This brings me to another point. One year ago we had a discussion on The > > Haskell Mailing List concerning arrows. (The subject of the mails was just > > "arrows".) The point was that it seemed strange to me that first and second > > are included in the basic arrow class Arrow while left and right have their > > extra class ArrowChoice. Not only that it seemed strange to me but it made > > impossible to make Parser baseMonad an instance of Arrow. Parser baseMonad > > has nice implementations of pure and (>>>) but none of first or second. > > I agree. My own Arrow module hierarchy looks more or less like this: > > class Compositor comp where [...] > class (Compositor arrow) => Arrow arrow where [...] > class (Arrow arrow) => ProductArrow arrow where [...] > class (Arrow arrow) => CoproductArrow arrow where [...] > class (ProductArrow arrow,CoproductArrow arrow) => FullArrow arrow > instance (ProductArrow arrow,CoproductArrow arrow) => FullArrow arrow > class (Arrow arrow) => ArrowFix arrow where [...] > class (FullArrow arrow) => ApplyArrow arrow where [...] On that topic, see below for what mine looks like (from HXML, ). I started off with Hughes' conventions, but for some reason could never remember the difference between &&& and ***, or between ||| and +++. I found &&&, >&<, |||, >|< to have better mnemonic value. This also frees up +++ for ArrowPlus, which -- in HXML applications -- is frequently used and should thus be easy to type. When using the ArrowChoice operators, I kept tripping over all the 'Either' coproduct types, so added some syntactic sugar (borrowed from HaXML): data Choice a = a :> a class (Arrow a) => ArrowChoice a where [ ... ] ( ?>) :: (b -> Bool) -> Choice (a b c) -> a b c (>?>) :: a b Bool -> Choice (a b c) -> a b c I found "p ?> f :> g" much more pleasant to use. (I also like the idea of splitting the product operators out of the base Arrow class -- will consider doing that in my library). -- infixr 5 +++ infixr 3 >&<, &&& infixr 2 >|<, |||, ?>, >?>, :> infixl 1 >>> class Arrow a where arr :: (b -> c) -> a b c (>>>) :: a b c -> a c d -> a b d apfst :: a b c -> a (b,x) (c,x) apsnd :: a b c -> a (x,b) (x,c) (>&<) :: a b c -> a d e -> a (b,d) (c,e) (&&&) :: a b c -> a b d -> a b (c,d) liftA2 :: (b -> c -> d) -> a e b -> a e c -> a e d aConst :: c -> a b c idArrow :: a b b -- Minimal implementation: arr, >>>, apfst or >&< data Choice a = a :> a class (Arrow a) => ArrowChoice a where apl :: a b c -> a (Either b d) (Either c d) apr :: a b c -> a (Either d b) (Either d c) (>|<) :: a b c -> a d e -> a (Either b d) (Either c e) (|||) :: a b c -> a d c -> a (Either b d) c ( ?>) :: (b -> Bool) -> Choice (a b c) -> a b c (>?>) :: a b Bool -> Choice (a b c) -> a b c -- Minimal implementation: >|< or apl class (Arrow a) => ArrowApply a where app :: a (a b c,b) c class (Arrow a) => ArrowZero a where aZero :: a b c aMaybe :: a (Maybe c) c aGuard :: (b -> Bool) -> a b b class (Arrow a) => ArrowPlus a where (+++) :: a b c -> a b c -> a b c --Joe English jenglish@flightlab.com From marta@uol.com.br Sun Jun 29 02:20:10 2003 From: marta@uol.com.br (Marta) Date: Sun, 29 Jun 2003 01:20:10 Subject: Bom dia haskell-cafe Message-ID: <20030629042007.C28E2421EEB@www.haskell.org> From chak@cse.unsw.edu.au Sun Jun 29 09:34:38 2003 From: chak@cse.unsw.edu.au (Manuel M T Chakravarty) Date: Sun, 29 Jun 2003 18:34:38 +1000 (EST) Subject: haskell array access In-Reply-To: <200306271210.57855.Shawn@Garbett.org> References: <3EFB6E9F.8040709@informatik.uni-muenchen.de> <200306271210.57855.Shawn@Garbett.org> Message-ID: <20030629.183438.607975769.chak@cse.unsw.edu.au> "Shawn P. Garbett" wrote, > I redid both programs to make them equivalent in action. The haskell program > was not actually summing the results, the C program was not checking array > bounds (Haskell does), the C program did not initialize the array and the C > program didn't print the result. > > Times on my laptop (Crusoe 933): > > 62.061s : Haskell (Array -O2) Note: lot's 'o disk grinding! > 18.231s : Haskell (UArray -O2) > 18.108s : Haskell (UArray -O2 -fvia-c) > 17.443s : Haskell (UArray -O2 -funfolding-update-in-place) > 0.807s : C (-O3 without bound check) > 1.127s : C (-O3 with bound check) > > At best case for Haskell, 15.5 times slower. The thing about bounds checking, > in Haskell it's always there. In C, you might have it, you might not there is > no certainty by the language, only by design and implementation. So with C, > one is free to live dangerously. The first two sections of http://www.cse.unsw.edu.au/~chak/papers/CK03.html also contain an analysis of some of the overheads in Haskell array codes compiled with GHC. Cheers, Manuel From basvandijk@home.nl Sun Jun 29 22:50:02 2003 From: basvandijk@home.nl (Bas van Dijk) Date: Sun, 29 Jun 2003 23:50:02 +0200 Subject: UML diagrams of Haskell Message-ID: <200306292350.03235.basvandijk@home.nl> Hi, It's maybe a weird question but do there exist UML diagrams of the Haskell language. They don't necessarily have to be UML diagrams, as long as they show the different concepts in the language (i.e.: functions, datatypes, patterns, etc.) and the relations between them(i.e.: a function consists of other functions, functions have a type). Bas. From t-hald@microsoft.com Mon Jun 30 05:17:10 2003 From: t-hald@microsoft.com (Hal Daume) Date: Sun, 29 Jun 2003 21:17:10 -0700 Subject: UML diagrams of Haskell Message-ID: <935F630FDD8A7F4CB1A0412C7CA4371405ED06F8@RED-MSG-10.redmond.corp.microsoft.com> There's something like UML, called FAD (Functional Analysis and Design, I believe). It was the topic of Daniel Russell's PhD thesis. See http://www.cs.kent.ac.uk/pubs/2001/1152/index.html for more. -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume > -----Original Message----- > From: haskell-cafe-admin@haskell.org=20 > [mailto:haskell-cafe-admin@haskell.org] On Behalf Of Bas van Dijk > Sent: Sunday, June 29, 2003 2:50 PM > To: HaskellCafe Mailinglist > Subject: UML diagrams of Haskell >=20 >=20 > Hi, >=20 > It's maybe a weird question but do there exist UML diagrams=20 > of the Haskell=20 > language.=20 > They don't necessarily have to be UML diagrams, as long as=20 > they show the=20 > different concepts in the language (i.e.: functions,=20 > datatypes, patterns,=20 > etc.) and the relations between them(i.e.: a function=20 > consists of other=20 > functions, functions have a type). >=20 > Bas. >=20 > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe >=20 From simonpj@microsoft.com Mon Jun 30 08:47:57 2003 From: simonpj@microsoft.com (Simon Peyton-Jones) Date: Mon, 30 Jun 2003 08:47:57 +0100 Subject: Arrow Classes Message-ID: <4B93206CA3C55D4F96A61C9B1DC80DE30C2B8C@EUR-MSG-03.europe.corp.microsoft.com> It may interest you guys to know that Ross Paterson and I have just put syntactic support for arrows into GHC. It's only in the CVS version at the moment, and is not documented at all, but those things will come. The type error messages should, I hope, be a lot better than those one can get by type checking pre-processed code. Simon | -----Original Message----- | From: haskell-cafe-admin@haskell.org [mailto:haskell-cafe-admin@haskell.org] On Behalf Of Joe | English | Sent: 28 June 2003 17:01 | To: haskell-cafe@haskell.org | Subject: Re: Arrow Classes |=20 |=20 | Ashley Yakeley wrote: | > Wolfgang Jeltsch wrote: | > | > > This brings me to another point. One year ago we had a discussion on The | > > Haskell Mailing List concerning arrows. (The subject of the mails was just | > > "arrows".) The point was that it seemed strange to me that first and second | > > are included in the basic arrow class Arrow while left and right have their | > > extra class ArrowChoice. Not only that it seemed strange to me but it made | > > impossible to make Parser baseMonad an instance of Arrow. Parser baseMonad | > > has nice implementations of pure and (>>>) but none of first or second. | > | > I agree. My own Arrow module hierarchy looks more or less like this: | > | > class Compositor comp where [...] | > class (Compositor arrow) =3D> Arrow arrow where [...] | > class (Arrow arrow) =3D> ProductArrow arrow where [...] | > class (Arrow arrow) =3D> CoproductArrow arrow where [...] | > class (ProductArrow arrow,CoproductArrow arrow) =3D> FullArrow = arrow | > instance (ProductArrow arrow,CoproductArrow arrow) =3D> FullArrow arrow | > class (Arrow arrow) =3D> ArrowFix arrow where [...] | > class (FullArrow arrow) =3D> ApplyArrow arrow where [...] |=20 |=20 | On that topic, see below for what mine looks like | (from HXML, ). |=20 | I started off with Hughes' conventions, but for some | reason could never remember the difference between &&& and ***, | or between ||| and +++. I found &&&, >&<, |||, >|< to have | better mnemonic value. This also frees up +++ for ArrowPlus, | which -- in HXML applications -- is frequently used and should | thus be easy to type. |=20 | When using the ArrowChoice operators, I kept tripping over all | the 'Either' coproduct types, so added some syntactic sugar | (borrowed from HaXML): |=20 | data Choice a =3D a :> a | class (Arrow a) =3D> ArrowChoice a where | [ ... ] | ( ?>) :: (b -> Bool) -> Choice (a b c) -> a b c | (>?>) :: a b Bool -> Choice (a b c) -> a b c |=20 | I found "p ?> f :> g" much more pleasant to use. |=20 | (I also like the idea of splitting the product operators out of | the base Arrow class -- will consider doing that in my library). |=20 | -- |=20 | infixr 5 +++ | infixr 3 >&<, &&& | infixr 2 >|<, |||, ?>, >?>, :> | infixl 1 >>> |=20 | class Arrow a where | arr :: (b -> c) -> a b c | (>>>) :: a b c -> a c d -> a b d | apfst :: a b c -> a (b,x) (c,x) | apsnd :: a b c -> a (x,b) (x,c) | (>&<) :: a b c -> a d e -> a (b,d) (c,e) | (&&&) :: a b c -> a b d -> a b (c,d) | liftA2 :: (b -> c -> d) -> a e b -> a e c -> a e d | aConst :: c -> a b c | idArrow :: a b b | -- Minimal implementation: arr, >>>, apfst or >&< |=20 | data Choice a =3D a :> a | class (Arrow a) =3D> ArrowChoice a where | apl :: a b c -> a (Either b d) (Either c d) | apr :: a b c -> a (Either d b) (Either d c) | (>|<) :: a b c -> a d e -> a (Either b d) (Either c e) | (|||) :: a b c -> a d c -> a (Either b d) c | ( ?>) :: (b -> Bool) -> Choice (a b c) -> a b c | (>?>) :: a b Bool -> Choice (a b c) -> a b c | -- Minimal implementation: >|< or apl |=20 | class (Arrow a) =3D> ArrowApply a where | app :: a (a b c,b) c |=20 | class (Arrow a) =3D> ArrowZero a where | aZero :: a b c | aMaybe :: a (Maybe c) c | aGuard :: (b -> Bool) -> a b b |=20 | class (Arrow a) =3D> ArrowPlus a where | (+++) :: a b c -> a b c -> a b c |=20 |=20 |=20 | --Joe English |=20 | jenglish@flightlab.com | _______________________________________________ | Haskell-Cafe mailing list | Haskell-Cafe@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-cafe From simonpj@microsoft.com Mon Jun 30 09:13:52 2003 From: simonpj@microsoft.com (Simon Peyton-Jones) Date: Mon, 30 Jun 2003 09:13:52 +0100 Subject: Template Haskell question Message-ID: <4B93206CA3C55D4F96A61C9B1DC80DE30C2B9A@EUR-MSG-03.europe.corp.microsoft.com> Yes, sorry, as Ian says, type splices just aren't implemented at the moment. The error message is uninformative. =20 This is useful info though -- someone wants type splices! Simon | -----Original Message----- | From: haskell-cafe-admin@haskell.org [mailto:haskell-cafe-admin@haskell.org] On Behalf Of Ashley | Yakeley | Sent: 27 June 2003 23:57 | To: haskell-cafe@haskell.org | Subject: Template Haskell question |=20 | Can anyone tell me what's wrong with this? |=20 | -- ghc -fglasgow-exts -c TH.hs | module TH where | { | import Language.Haskell.THSyntax; |=20 | class HasZero a where | { | zero :: a; | }; |=20 | aninstance :: TypQ -> Q [Dec]; | aninstance t =3D [d| |=20 | instance HasZero $t where -- error here | { | zero =3D 0; | }; |=20 | |]; |=20 | $(aninstance [t|Int|]) | $(aninstance [t|Integer|]) | } |=20 |=20 | $ ghc -fglasgow-exts -c TH.hs | TH.hs:14: Malformed context in instance header |=20 | All I want to do is spin off a number instances for a number of types... |=20 | -- | Ashley Yakeley, Seattle WA |=20 | _______________________________________________ | Haskell-Cafe mailing list | Haskell-Cafe@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-cafe From maeder@tzi.de Mon Jun 30 11:31:26 2003 From: maeder@tzi.de (Christian Maeder) Date: Mon, 30 Jun 2003 12:31:26 +0200 Subject: Simple monads In-Reply-To: <200306271807.49983.wolfgang@jeltsch.net> References: <20030626175743.00001bf5.ddarius@hotpop.com> <3EFC22B4.4010405@tzi.de> <200306271807.49983.wolfgang@jeltsch.net> Message-ID: <3F00117E.40103@tzi.de> >>The portable parts of Control.Monad.State (that are sufficient for most >>cases) should be in an extra module (maybe called Control.Monad.StateTypes). >>In addition further non-overloaded names for put, get, gets and modify would >>be needed (maybe putState, getState, etc.) > > I fear, this would complicate the module structure too much. I only suggest to split a (comparatively large) module Control.Monad.State into two modules. I think that is rather appropriate. (I'm willing to supply these modules.) I've already extracted a portable part, because I wanted to try out the nhc98 tracer. Christian From djrussell@kingston.ac.uk Mon Jun 30 11:57:36 2003 From: djrussell@kingston.ac.uk (Daniel Russell) Date: Mon, 30 Jun 2003 11:57:36 +0100 (BST) Subject: UML diagrams of Haskell In-Reply-To: <200306292350.03235.basvandijk@home.nl> from "Bas van Dijk" at Jun 29, 2003 11:50:02 PM Message-ID: <200306301057.h5UAvaJF016490@helios.king.ac.uk> Bas FAD does not use UML diagrams but it's own (graphical) units, and provides the functionality that you request. I am currently developing a CASE tool to support FAD -- although it is slow progress! Regards Dan Russell > > Hi, > > It's maybe a weird question but do there exist UML diagrams of the Haskell > language. > They don't necessarily have to be UML diagrams, as long as they show the > different concepts in the language (i.e.: functions, datatypes, patterns, > etc.) and the relations between them(i.e.: a function consists of other > functions, functions have a type). > > Bas. > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe > From ross@soi.city.ac.uk Mon Jun 30 16:04:56 2003 From: ross@soi.city.ac.uk (Ross Paterson) Date: Mon, 30 Jun 2003 16:04:56 +0100 Subject: Arrow Classes In-Reply-To: <200306271927.36405.wolfgang@jeltsch.net> References: <20030626175743.00001bf5.ddarius@hotpop.com> <200306271927.36405.wolfgang@jeltsch.net> Message-ID: <20030630150455.GA8927@soi.city.ac.uk> On Fri, Jun 27, 2003 at 07:27:36PM +0200, Wolfgang Jeltsch wrote: > This brings me to another point. One year ago we had a discussion on The > Haskell Mailing List concerning arrows. (The subject of the mails was just > "arrows".) The point was that it seemed strange to me that first and second > are included in the basic arrow class Arrow while left and right have their > extra class ArrowChoice. Not only that it seemed strange to me but it made it > impossible to make Parser baseMonad an instance of Arrow. Parser baseMonad > has nice implementations of pure and (>>>) but none of first or second. Your parser type is strange candidate for an arrow: the input (token) type occurs in both positive and negative positions in the type. And does it satisfy identity >>> f = f? > Currently, I use my own Arrow module which provides an arrow class, that > doesn't include first and second. I'm really not happy with using a > replacement for a module from the hierarchical libraries. Is there any chance > of changing the class structure of Control.Arrow? The point about symmetry is a fair one, but unfortunately the Haskell class system imposes a cost on fine-grained class hierarchies, so we must ask what would be gained. You may have extra instances, but are there extra client programs written to the new interfaces? John Hughes asked this last time, and you pointed out instance PreArrow a => Functor (a b) where fmap f a = a >>> arr f but is that it?