*safe* coerce: four methods compared
This is a "Related Work" section of the previous message. We compare three main methods of achieving safe casts. It seems that the method proposed in the earlier message is quite different -- especially in terms of extensibility. In this message, we compare the extensibility of four techniques. Stephanie Weirich ICFP'00 paper points out another solution, which relies on mutable IORefs. Since that technique can only be used with IO monad, we do not consider it here. Some of the methods below require type classes and algebraic datatype declarations. Some require only an algebraic datatype, or only a typeclass. In either case, we run into an extensibility problem: to add support for a new datatype, we must either add an instance declaration, or a new alternative to the datatype declaration. These are non-trivial, non-modular extensions. For example, when we add a new alternative to a datatype declaration, we must physically update the corresponding file. We must then re-compile all dependent modules. Surprisingly, the solution in the earlier message is free from these drawbacks. We can extend the type heap in a modular fashion. We do not need to alter type or data declarations. It seems our type heaps are sort of reified lists of instances. There appear to be a duality between typeclasses and our type heaps. Only our type heaps are first-class. The idea behind all type-safe casts is simple: to cast a value of a type 'a' into a target type 'b', we inject the value into some universe and then project it to the target type 'b'. To illustrate the differences in implementations of that idea, we will be using James Cheney and Ralf Hinze's example: a generic comparison function. To avoid unnecessary complications, we limit ourselves to built-in and scalar types. Extensions to products, exponential, recursive and polymorphic types are possible, but too messy. We also will not consider existential types, so we avoid introducing type classes if they are not needed in the static case. This whole message is self-contained, and can be loaded as it is in GHCi, given the flags -fglasgow-exts -fallow-undecidable-instances -fallow-overlapping-instances Approach 1: Tcl approach The universal type is a string. The values to cast must belong to the class Show and the class Read. The injection and projection functions are trivial: > sh_inj x = show x > sh_prj x = read x Generic equality and the cast functions are trivial as well: > sh_gequal x y = sh_inj x == sh_inj y > sh_cast x = sh_prj $ sh_inj x Here's the test: > sh_test1 = [sh_gequal 1 2, sh_gequal True True, sh_gequal 'a' 'b'] To add support for a new datatype, we have to place that datatype in the class Show and the class Read. That is, we have to add the corresponding instance declarations _and_ we have to implement methods 'show' and 'read'. Functions sh_gequal and sh_cast do not have to be modified. The Tcl approach is also the most generous with respect to type equivalence: for example, Int and Integer are considered equivalent, and sh_cast may cast between them. Incidentally, when GHC can derive Binary, this approach becomes far more appealing. Approach 2: The universe is the tagged union > data TU = TChar Char | TBool Bool | TInt Int > > class TURepr t where > tu_inj:: t -> TU > tu_prj:: TU -> t > > instance TURepr Char where > tu_inj = TChar > tu_prj (TChar x) = x > > instance TURepr Bool where > tu_inj = TBool > tu_prj (TBool x) = x > > instance TURepr Int where > tu_inj = TInt > tu_prj (TInt x) = x > > tu_gequal x y = cmp (tu_inj x) (tu_inj y) > where > cmp (TChar x) (TChar y) = x == y > cmp (TBool x) (TBool y) = x == y > cmp (TInt x) (TInt y) = x == y > > tu_cast x = tu_prj $ tu_inj x > > tu_test1 = [tu_gequal (1::Int) (2::Int), tu_gequal True True, > tu_gequal 'a' 'b'] To add support for a new datatype, we have to add a new alternative to the declaration of the datatype TU and we have to add a new instance for the class TURepr (with the implementation of the tu_inj and tu_proj methods). We also have to add another clause to the tu_gequal function. Clearly this is the least extensible approach. Approach 3: by Cheney and Ralf Hinze's The universe is a set of inject/project pairs > data IPP a = IPPInt (a->Int) (Int->a) > | IPPChar (a->Char) (Char->a) > | IPPBool (a->Bool) (Bool->a) > > ipp_gequal (IPPInt prj inj) x y = prj x == prj y > ipp_gequal (IPPChar prj inj) x y = prj x == prj y > ipp_gequal (IPPBool prj inj) x y = prj x == prj y > > ipp_cast (IPPInt xprj xinj) x (IPPInt yprj yinj) = yinj $ xprj x > -- more should follow... > > ipp_test1 = [ipp_gequal (IPPInt id id) (1::Int) (2::Int), > ipp_gequal (IPPBool id id) True True, > ipp_gequal (IPPChar id id) 'a' 'b'] To add a new primitive datatype, we should modify the declaration of the datatype IPP and add a new alternative. We also need to add cl
Re: *safe* coerce, for regular and existential types
I admire the elegancy of your code which makes the changes to add new data types minimum. There is one question I want to ask: Does this technique extend to polymophic types? Let's say we have the following type: > data D a = C | D a Is it possible to index the type D a? Or there is some fundmental limitations which make it not achievable by Haskell type classes? -W-M- @ @ | \_/ On Thu, 31 Jul 2003 [EMAIL PROTECTED] wrote: > > This message describes functions safeCast and sAFECoerce implemented > in Haskell98 with common, pure extensions. The functions can be used > to 'escape' from or to existential quantification and to make > existentially-quantified datatypes far easier to deal with. Unlike > Dynamic, the present approach is pure, avoids unsafeCoerce and > unsafePerformIO, and permits arbitrary multiple user-defined typeheaps > (finite maps from types to integers and values). > > An earlier message [1] introduced finite type maps for > purely-functional conversion of monomorphic types to unique > integers. The solution specifically did not rely on Dynamic and > therefore is free from unsafePerformIO. This message shows that the > type maps can be used for a safe cast, in particular, for laundering > existential types. The code in this message does NOT use > unsafePerformIO or unsafeCoerce. To implement safe casts, we define a > function sAFECoerce -- which works just like its impure > counterpart. However the former is pure and safe. sAFECoerce is a > library function expressed in Haskell with common extension. The > safety of sAFECoerce is guaranteed by the typechecker itself. > > This whole message is self-contained, and can be loaded as it is in > GHCi, given the flags > -fglasgow-exts -fallow-undecidable-instances -fallow-overlapping-instances > > This message was inspired by Amr Sabry's problem on existentials. In > fact, it answers an unstated question in Amr Sabry's original message. > > > It has been observed on this list that existentially-quantified > datatypes are not easy to deal with [2]. For example, suppose we have > a value of a type > > > data EV = forall a. (TypeRep a TI)=> EV a > > (please disregard the second argument of TypeRep for a moment). > > The constructor EV wraps a value. Suppose we can guess that the > wrapped value is actually a boolean. Even if our guess is correct, we > *cannot* pass that value to any function of booleans: > > *> *Main> case (EV False) of (EV x) -> not x > *> > *> :1: > *> Inferred type is less polymorphic than expected > *> Quantified type variable `a' is unified with `Bool' > *> When checking an existential match that binds > *> x :: a > *> and whose type is EV -> Bool > *> In a case alternative: (EV x) -> not x > > A quantified type variable cannot be unified with any regular type -- > or with another quantified type variable. Values of existentially > quantified types cannot be passed to monomorphic functions, or to > constrained polymorphic functions (unless all their constrains have > been mentioned in the declaration of the existential). That limitation > guarantees safety -- on the other hand, it significantly limits the > convenience of existential datatypes [2]. > > To overcome the limitation, it _seemed_ that we had to sacrifice > purity. If we are positive that a particular existentially quantified > value has a specific type (e.g., Bool), we can use unsafeCoerce to > cast the value into the type Bool [3]. This approach is one of the > foundations of the Dynamic library. The other foundation is an ability > to represent a type as a unique run-time value, provided by the > methods of the class like TypeRep. Given an existentially quantified > value and a value of the desired type, Dynamic compares type > representations of the two values. If they are the same, we can > confidently use unsafeCoerce to cast the former into the type of the > latter. > > This works, yet leaves the feeling of dissatisfaction. For one thing, > we had to resort to an impure feature. More importantly, we placed our > trust in something like TypeRep and its members, that they give an > accurate and unique representation of types. But what if they lie to > us, due to a subtle bug in their implementation? What if they give the > same representation for two different types? unsafeCoerce will do its > dirty work nevertheless. Using the result would lead to grave > consequences, however. > > This message describes sAFECoerce and the corresponding safe cast. > Both functions convert the values of one type into the target type. > One or both of these types may be existentially quantified. When the > source and the target types are the same, both functions act as the > identity function. The safe cast checks that the type representations > of the source and the target types are the same. If they are, it > invokes sAFECoerce. Otherwise, we monadically fail. The function > sAFECoerce does the conversion without any type checkin
Re: Libraries and hierarchies
On Fri, Aug 01, 2003 at 05:00:55PM +0100, Keith Wansbrough wrote: > [stuff about GUIDs] > > Careful! There are two things one might tie GUIDs to. > > You could compute a hash of (or associate a GUID with) the *interface*, > or the *implementation*. These are different things. Until we know > which we want, we should support both. yes, which is why each library can export an arbitrary number of GUIDs. Oddly enough, I considered doing what you mentioned below (a hash of the interface). but chose not to so that the same interface can be exported under several GUIDs. this reflects the fact that there could be hidden assumptions (such as relying on bugs) in interfaces which should be reflected in the GUID. I also wanted the tool to have simple semantics relative the haskell base language. thinking of it as modules just having multiple Module declarations and export lists should make it easy to adopt. plus, this was much easier to implement as a first stab at the problem :) > One might reasonably say "this program needs version X of the > interface". That is, we don't care how it's implemented, but it had > better export these functions at these types. > But one might also reasonably say "this program needs version Y of the > implementation". That is, it requests a particular *implementation* - > maybe it depends on certain bugs that are fixed in that version (or are > not fixed!). Or it's only been tested against that implementation, and > it wants to provide some certification guarantees ("This software is > DoD-certified to give appropriate results with specified inputs"). The idea then is that you would hsguid -g twice to generate an implementation ID and an interface id. old implementations could be archived and their interface id deleted. > A side point is that GUIDs can be generated in two ways: > > 1. The traditional way: make up a 128-bit random number and insert it > into the interface or implementation (as appropriate). Use this as the > name for that thing. > > 2. The nifty way: have the compiler compute a hash (SHA-1 or MD5) of > the interface or implementation (as appropriate). Use this as the name > for that thing. Yeah, that might be a good way to do it if I could have compiler support, but I would need to be able to append some 'salt' to take care of hidden assumptions not reflected in the raw interface. I actually implemented something like this for datatypes, based on XDR... hmm.. http://haskell.org/pipermail/haskell-cafe/2001-September/002215.html > Option (2) has the advantage that it's one step shorter, and it's > safer: with (1), you can generate one GUID but accidentally use it on > two distinct interfaces / implementations; with (2), this is > (essentially) impossible (although it may be possible to achieve a > collision intentionally; malice is a separate issue that should be > addressed in other ways). eh. I don't think the random collision is a real concern, at worst, hsguid spits out an error and you angrily email the authors for doing the equivalant of winning the lottery 10 times in a row :) problem resolved just by copying the offending pragma with a new id and use that one. > For (2), we need to agree what to hash. The options are basically "the > source text of the module" (or some sub-part of it for the interface > case), or "the abstract syntax tree of the module". The latter is > probably nicer, but requires some agreement between compiler writers if > it is to be valid across compilers. what I did was implement a Hash class, which had a single function which returned a hash, the hash was constant if the type was a terminal, and its type hashed with all its childrens types if it was a node. recursive types were detected by drift and explicitly broken. although probably for this, the easiest thing would be to hash the cannonicalized export list (with types). but not for hsguid. but perhaps for some other tool which does a better job of generating hsguid compatable pragmas. > For background to this discussion, see our forthcoming ICFP paper, > > James J. Leifer, Gilles Peskine, Peter Sewell, Keith Wansbrough (2003). > Global Abstraction-Safe Marshalling with Hash Types > > which is available at > > http://www.cl.cam.ac.uk/~kw217/research/paper-abstracts.html#Leifer*03:G > lobal ooh. looks interesting. will read. I have really wanted something like this for haskell for a while. John -- --- John Meacham - California Institute of Technology, Alum. - [EMAIL PROTECTED] --- ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Libraries and hierarchies
[stuff about GUIDs] Careful! There are two things one might tie GUIDs to. You could compute a hash of (or associate a GUID with) the *interface*, or the *implementation*. These are different things. Until we know which we want, we should support both. Why? One might reasonably say "this program needs version X of the interface". That is, we don't care how it's implemented, but it had better export these functions at these types. But one might also reasonably say "this program needs version Y of the implementation". That is, it requests a particular *implementation* - maybe it depends on certain bugs that are fixed in that version (or are not fixed!). Or it's only been tested against that implementation, and it wants to provide some certification guarantees ("This software is DoD-certified to give appropriate results with specified inputs"). A side point is that GUIDs can be generated in two ways: 1. The traditional way: make up a 128-bit random number and insert it into the interface or implementation (as appropriate). Use this as the name for that thing. 2. The nifty way: have the compiler compute a hash (SHA-1 or MD5) of the interface or implementation (as appropriate). Use this as the name for that thing. Option (2) has the advantage that it's one step shorter, and it's safer: with (1), you can generate one GUID but accidentally use it on two distinct interfaces / implementations; with (2), this is (essentially) impossible (although it may be possible to achieve a collision intentionally; malice is a separate issue that should be addressed in other ways). For (2), we need to agree what to hash. The options are basically "the source text of the module" (or some sub-part of it for the interface case), or "the abstract syntax tree of the module". The latter is probably nicer, but requires some agreement between compiler writers if it is to be valid across compilers. For background to this discussion, see our forthcoming ICFP paper, James J. Leifer, Gilles Peskine, Peter Sewell, Keith Wansbrough (2003). Global Abstraction-Safe Marshalling with Hash Types which is available at http://www.cl.cam.ac.uk/~kw217/research/paper-abstracts.html#Leifer*03:G lobal Comments? --KW 8-) -- Keith Wansbrough <[EMAIL PROTECTED]> http://www.cl.cam.ac.uk/users/kw217/ University of Cambridge Computer Laboratory. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Use of H98 FFI
> "Derek" == Derek Elkins <[EMAIL PROTECTED]> writes: Derek> Derek> Except that I would probably mapM_ over a list of chunks, I don't Derek> see what the problem is with your second version of the code is. The second version allocates memory like crazy, so much that the pokeByteOff and castCharToCChar version becomes twice roughly twice as fast. Here are some figures [all compiled with -O2, otherwise version c looses badly]: s - hash in one go a - chunks of 512 characters c - byte-wise [on 51MB String] Main a : 58.730u 1.440s 1:00.13 100.0% 0+0k 0+0io 182pf+0w Main c : 29.370u 0.740s 0:30.07 100.1% 0+0k 0+0io 182pf+0w [on 32MB String] Main a : 37.500u 1.100s 0:38.58 100.0% 0+0k 0+0io 182pf+0w Main c : 18.790u 0.510s 0:19.43 99.3%0+0k 0+0io 182pf+0w [on 500k String] Main s : 0.560u 0.120s 0:00.66 103.0%0+0k 0+0io 182pf+0w Main a : 0.610u 0.010s 0:00.59 105.0%0+0k 0+0io 182pf+0w Main c : 0.290u 0.000s 0:00.27 107.4%0+0k 0+0io 182pf+0w So the generally most efficient seems to be to use c, but I suspect that further gains would be possible if this variant were implemented at a lower level. Hence the proposal for newCStringPart. -Peter ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Libraries and hierarchies
confluence! Inspired by some posts the other day I implemented an immutable GUID naming scheme for interfaces with Haskell. I thought it would require compiler support, but it turns out a good 90% solution can be done as a separate program quite nicely and there are not too tough workarounds for the other 10%. http://repetae.net/john/computer/haskell/hsguid/ This is not really the same as your proposal, but is somewhat related and addresses many of the same issues. (and might be a bit lighter weight) actually, they would probably mix well as your proposed system could just use the same GUID pragmas hsguid uses as input. Let me know what y'all think. library developers, add a GUID to your code. it's easy and takes no resources, but could save users of your library a lot of hassle. :) John -- --- John Meacham - California Institute of Technology, Alum. - [EMAIL PROTECTED] --- ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
CSMR 2004 - CALL FOR PAPERS
8th European Conference on Software Maintenance and Reengineering March 24 - 26, 2004 Tampere, Finland Call for Papers The European Conference on Software Maintenance is the premier European conference on the theory and practice of evolution, maintenance and reengineering of software systems. Now approaching its eight edition, we invite you to contribute to the discussion on the issues of developing maintainable systems and evolving, migrating and reengineering existing ones. The theme of this year's conference will be "the maintenance and evolution of the software architecture". Although nowadays the importance of designing a robust software architecture is well-understood by the industry, the activities related to its maintenance and evolution are rather immature and unsystematic. We solicit contributions on this theme. The topics of interest include, but are not restricted to: Evolution, maintenance and reengineering Software architecture recovery and evolution Automated software maintenance Software metrics Economical aspects of software evolution Pattern languages for evolution, maintenance and reengineering Experience reports (successes and failures) Tools and enabling technologies for evolution, maintenance and reengineering tools Formal methods to support evolution, maintenance and reengineering System assessment for evolution, maintenance and reengineering Migration, wrapping and interfacing legacy systems Dealing with legacy systems towards new technologies Data reengineering Reverse engineering of embedded systems Web-site evolution, maintenance and reengineering Migration towards Web-services Evaluation and assessment of reverse engineering tools Maintenance of open source projects Product family migration and maintenance One of the basic intentions of this conference is to offer a European forum for discussion and exchange of experiences among researchers and practitioners. Therefore, besides academics, we kindly invite all those in companies developing maintenance tools, offering reengineering services or going through legacy systems migration experiences to contribute by submitting papers or presenting innovative tools, solutions or experience reports. This conference is not limited to European participants. Authors from outside Europe are also welcomed. SUBMISSIONS Two types of submissions will be accepted: full length papers (not exceeding 4000 words in length and including a 150-200 word abstract) and short papers (not exceeding 2000 words in length and including a 75-100 word abstract) The official langue is Enligh. Authors are requested to submit electronically a PostScript or PDF version of their papers. In addition, they should send a separate file containing the title of the paper, full names, affiliations, postal and e-mail addresses, fax and telephone numbers of all authors. IEEE Computer Society Press will publish the CSMR 2004 Proceedings. Full papers exceeding 10 pages (4 pages for short papers) will be charged for pages in excess. Authors of accepted papers must sign the IEEE copyright form. At least one author of each accepted submission must register and present the paper at the conference. The Program Committee will select the best paper of the conference and a prize will be awarded for the winner. The Program Committee will select the winner and a formal presentation of the winner will be made in Tampere at CSMR 2004. SPECIAL SESSIONS Sessions of special interest, workshops, and tool demonstrations are welcomed. Please send suggestions to the program chair before the submissions closing date. SUBMISSION METHOD For submission details please visit the conference website: http://www.cs.tut.fi/~csmr2004/. Papers can also be submitted via email to the program chair. FINAL FORMAT OF PAPERS Accepted papers must be revised to conform with IEEE style guidelines at http://www.computer.org/cspress/instruct.htm. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Submission deadline SNPD03 approaching
== CALL FOR PAPERS Fourth International Conference on Software Engineering, Artificial Intelligence, Networking, and Parallel/Distributed Computing (SNPD03) October 16-18, 2003 Luebeck, Germany http://www.isp.uni-luebeck.de/snpd03/index.htm == Scope and Topics The conference provides an international forum for scientists to present research results in the areas of software engineering, artificial intelligence, networking and parallel/distributed computing. The conference particularly welcomes contributions at the junction of theory and practice disseminating basic research with immediate impact on practical applications. The conference will cover a broad range of topics including theory, methods, applications, and tools. The conference concentrates on software issues and is structured into the following tracks: Software Engineering and Information Engineering Component-Based Software Engineering Internet Technology and Applications Information Management Systems Software Engineering Education Parallel and Distributed Computing Communication Systems and Networks Mobile and Wireless Computing Visual and Multimedia Computing Artificial Intelligence, Data Mining, Knowledge Discovery Neural Networks and Genetic Algorithms Economic and Financial Systems Control Systems Image, Acoustic, Speech and Signal Processing Venue = After Reims (2000), Nagoya (2001) and Madrid (2002) this years SNPD conference will be held at the Moevenpick Hotel in Luebeck. The Hanseatic town of Luebeck is located in Northern Germany close to the Baltic Sea with frequent train connections to major airports. The medieval town was appointed as world cultural heritage by the United Nations. Important Deadlines === Full Paper Submission: August 15, 2003 Notification of Acceptance: September 10, 2003 Camera-ready Papers: September 24, 2003 Conference Proceedings & Journal Accepted papers limited to 8 pages will be published in the conference proceedings with ISBN. After the conference a selection of excellent papers will be published in a special issue of the International Journal of Computer and Information Science. For further details, please visit the conference web page http://www.isp.uni-luebeck.de/snpd03/index.htm. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: a breaking monad
On Fri, 1 Aug 2003 12:02:00 +0200 Tomasz Zielonka <[EMAIL PROTECTED]> wrote: > On Thu, Jul 31, 2003 at 05:15:33PM -0400, Derek Elkins wrote: > > On Thu, 31 Jul 2003 13:18:40 -0700 > > "Hal Daume" <[EMAIL PROTECTED]> wrote: > > > > > so, my questions are: does this exist in some other form I'm not > > > aware of? is there something fundamentally broken about this > > > (sorry for the pun)? any other comments, suggestions? > > > > This looks like a bizarre rendition of the Error/Exception monad. > > > > I believe the function "breakable" would be fairly accurately > > represented with '\b -> runErrorT b >>= either return return' and > > use throwError for break. > > I used the Cont(inuation) monad for similar purposes. This has an > advantage that you can choose a place to break (jump?) into, each > place having a possibly different type of return value. I was thinking of providing a Cont example too. > PS. Are there other uses of Cont monad? I've used it for resumptions, and I imagine you could use it to handle the CP in an "optimized" via CPS function, though that likely isn't worthwhile (heh). Hinze's Backtracking monad uses CPS but not the Cont monad, though it may be representable with ContT over Cont, I'm pretty sure shift/reset can get the same effect. Less immediately practical, I've experimented with shift/reset with it. I'm kind of interested in translating Filinsky's monadic reification and reflection into Haskell with the Cont(T) monad. This would probably have no real practical benefit (or would it... run-time changing?), I believe a similar effect usage-wise can be achieved by using a class for the monad parameter (MonadState/etc.) It would be more practical if a compiler internally supported a Cont(T) monad. Anyways, most of my uses of the Cont monad have been for my own personal entertainment, and usually I break the abstraction (using Control.Monad.Cont) to do the things I want. I don't know if I've ever written something that's used callCC that I kept. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: a breaking monad
On Thu, Jul 31, 2003 at 05:15:33PM -0400, Derek Elkins wrote: > On Thu, 31 Jul 2003 13:18:40 -0700 > "Hal Daume" <[EMAIL PROTECTED]> wrote: > > > so, my questions are: does this exist in some other form I'm not aware > > of? is there something fundamentally broken about this (sorry for the > > pun)? any other comments, suggestions? > > This looks like a bizarre rendition of the Error/Exception monad. > > I believe the function "breakable" would be fairly accurately > represented with '\b -> runErrorT b >>= either return return' and use > throwError for break. I used the Cont(inuation) monad for similar purposes. This has an advantage that you can choose a place to break (jump?) into, each place having a possibly different type of return value. Here's an example: module A where import Control.Monad.Cont import Control.Monad fun :: IO () fun = (`runContT` return) $ do r <- callCC $ \exit -> do r1 <- callCC $ \exit1 -> do r2 <- callCC $ \exit2 -> do r3 <- callCC $ \exit3 -> do x <- liftIO (readLn :: IO Int) when (x == 2) (exit2 "two") -- jump with a String when (x == 1) (exit1 1) -- jump with an Int when (x == 3) (exit3 ["three"]) -- with [String] (exit "other") return [] liftIO $ putStrLn $ "r3: " ++ show r3 exit1 3 -- jump with Int return "three" liftIO $ putStrLn $ "r2: " ++ show r2 return 2 liftIO $ putStrLn $ "r1: " ++ show r1 return (show r1) liftIO $ putStrLn $ "r: " ++ show r After running fun, type a number ([1..4]) and press Enter. PS. Are there other uses of Cont monad? Best regards, Tom -- .signature: Too many levels of symbolic links ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: *safe* coerce, for regular and existential types
[EMAIL PROTECTED] wrote: > > ... loads of cunning stuff omitted > Software-engineering-wise your approach suffers from an important weakness: a closed world assumption. The programmer has to maintain your "TI" and pass it on in all kinds of contexts for the array of types to be handled. I also had a type-safe and efficient cast in [1] with a CWA. (I guess it works fine for extensials.) My CWA was even more serious however. I use a class for casting whose declaration even depends on the array of types to be handled. On the positive side, I didn't need undecidable not even overlapping instances. Also, the programmer is not concerned with passing on any type seq like your "TI". I really admire your use of polymorphic lists (which are in fact kind of products) to get the problem of type sequences to the value level. Cool! Do you see any way to effectively remove this CWA? (Only then it could serve as a replacement of the current cast function.) If yes, would you expect that your approach is more efficient then the one taken in Data.Typeable? (We recently split up Data.Dynamics into Data.Dynamics and a more primitive module Data.Typeable which contains cast; see CVS) Is it obvious to see that fetching stuff from the type sequences would be indeed efficient for long PLists? Well, I guess the hard problem is the CWA anyway. Ralf [1] The Sketch of a Polymorphic Symphony http://homepages.cwi.nl/~ralf/polymorphic-symphony/ See the Larghetto movement It is trivial; it makes Stephanie Weirich's type-safe cast fit for nominal type analysis. -- Ralf Laemmel VU & CWI, Amsterdam, The Netherlands http://www.cs.vu.nl/~ralf/ http://www.cwi.nl/~ralf/ ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Use of H98 FFI
On 01 Aug 2003 09:44:14 +0200 Peter Thiemann <[EMAIL PROTECTED]> wrote: > I recently had my first exposure to Haskell's FFI when I was trying to > compute MD5 and SHA1 hashes using the existing C implementations. In > each case, the idea is to make the hash function available as function > > > md5 :: String -> String > > However, the naive implementation > > > md5_init md5_state > > n <- newCString str > > md5_append md5_state n (fromIntegral (length str)) > > md5_finish md5_state md5_digest > > does not scale to computing hashes of really long strings (50 MB, say, > as arising from reading a moderately big file), since it tries to > create a CString of that size, first! > > Trying to avoid the allocation of this giant CString requires to split > up the original string into smaller parts and convert each part to a > CString separately. Clearly, this task involves a lot of allocation, > essentially the input string needs to be copied part by part. > > Hence, I was wondering why the FFI only provides functionality to > convert an *entire* list of Char into a CString. For applications like > this hash computation, it would be advantageous to be able to specify > *how much* of the input string to marshall to the CString and have the > conversion function return the rest of the input string and the > CString. That is, in addition to > > > newCString :: String -> IO CString > > there should be > > > newCStringPart :: String -> Int -> IO (CStringLen, String) > > or even > > > toCStringPart :: String -> CStringLen -> IO (Int, String) > > where CStringLen describes a target buffer into which the String > argument is to be marshalled. (and similarly for other list types) > > Clearly, I can program this functionality by hand. But I have to > revert to byte-wise processing using pokeByteOff, castCharToCChar, and > so on. In addition, the optimizer does not seem to be very effective > on such code, so it seems advantageous to provide it in the library > already. > > But perhaps I'm overlooking something, so I'm appending the code I was > using below. > > -Peter Except that I would probably mapM_ over a list of chunks, I don't see what the problem is with your second version of the code is. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Re: Use of H98 FFI
Peter Thiemann wrote: md5 :: String -> String Hmmm, this should probably be: > md5 :: [Word8] -> [Word8] unless you really want the MD5 of the Unicode characters... Cheers, S. ___ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell
Use of H98 FFI
I recently had my first exposure to Haskell's FFI when I was trying to compute MD5 and SHA1 hashes using the existing C implementations. In each case, the idea is to make the hash function available as function > md5 :: String -> String However, the naive implementation > md5_init md5_state > n <- newCString str > md5_append md5_state n (fromIntegral (length str)) > md5_finish md5_state md5_digest does not scale to computing hashes of really long strings (50 MB, say, as arising from reading a moderately big file), since it tries to create a CString of that size, first! Trying to avoid the allocation of this giant CString requires to split up the original string into smaller parts and convert each part to a CString separately. Clearly, this task involves a lot of allocation, essentially the input string needs to be copied part by part. Hence, I was wondering why the FFI only provides functionality to convert an *entire* list of Char into a CString. For applications like this hash computation, it would be advantageous to be able to specify *how much* of the input string to marshall to the CString and have the conversion function return the rest of the input string and the CString. That is, in addition to > newCString :: String -> IO CString there should be > newCStringPart :: String -> Int -> IO (CStringLen, String) or even > toCStringPart :: String -> CStringLen -> IO (Int, String) where CStringLen describes a target buffer into which the String argument is to be marshalled. (and similarly for other list types) Clearly, I can program this functionality by hand. But I have to revert to byte-wise processing using pokeByteOff, castCharToCChar, and so on. In addition, the optimizer does not seem to be very effective on such code, so it seems advantageous to provide it in the library already. But perhaps I'm overlooking something, so I'm appending the code I was using below. -Peter MD5.hs Description: three interfaces to MD5