Re: [Haskell-cafe] Re: [Haskell] Simple IO Regions
Andrew Pimlott wrote: liftR :: (InRegion mark marks) = (h - m a) - Private mark h - Region marks m a liftR f (Private h) = Region $ f h This is not as safe. Try modifying your test2. Okay, I missed this... Have renamed the function unsafeLiftR... As you say still useful for building libraries provided you do not export the region code from the library that uses it. Of course an alternative is just to have an opaque/abstract handle, and not export the data-constructor. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Simple IO Regions
Taral wrote: On 1/17/06, Keean Schupke [EMAIL PROTECTED] wrote: Just made a few modifications and thought it might be useful to people. I have rewritten the functions as liftR and bracketR over a MonadIO monad interface (allowing monad-transformers to be used). I'm sorry, but what is Lib.Monad.MonadT? How does up3 work? MonadIO exists in Control.Monad.Trans. It didnt when I wrote the MonadIO stuff that I use! Here is the missing file ... I tried to put it all in one, but missed the use of up3. (see attached) Regards, Keean. {-# OPTIONS -fglasgow-exts -fallow-undecidable-instances -fallow-overlapping-instances #-} -- parser.hs: Copyright (C)2001,2002 Keean Schupke. -- -- Polymorphic monadic consumer based parser. module Lib.Monad.MonadT where import Control.Monad hiding (guard) -- class Runnable m n where run :: m - n instance Runnable (m a) (m a) where run = id instance Runnable (s - m a) (s - m a) where run = id class (Monad m,Monad (t m)) = MonadT t m where up :: m a - t m a up1 :: (m a - m a) - t m a - t m a up2 :: (m a - (b - m a) - m a) - t m a - (b - t m a) - t m a up3 :: (m a - (a - m b) - (a - m c) - m c) - t m a - (a - t m b) - (a - t m c) - t m c down :: t m a - m a up1 = undefined up2 = undefined up3 = undefined -- instance (Monad m,Monad n,MonadT t m,Runnable (m a) (n a)) = Runnable (t m a) (n a) where -- run = run . down instance (Monad m,MonadT t m,Monad (t m)) = Runnable (t m a) (m a) where run = down ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] Simple IO Regions
up3 is quite easy to define, but it is specific to the monad-transformer you are lifting through... see attached for definition for the state-monad-transformer. Keean. Taral wrote: On 1/18/06, Keean Schupke [EMAIL PROTECTED] wrote: It didnt when I wrote the MonadIO stuff that I use! Here is the missing file ... I tried to put it all in one, but missed the use of up3. (see attached) All I see is up3 = undefined... somehow I don't think that will work. As far as I know, (t m a - m a) is only possible for very specific monad transformers... -- Taral [EMAIL PROTECTED] Computer science is no more about computers than astronomy is about telescopes. -- Edsger Dijkstra {-# OPTIONS -fglasgow-exts -fallow-undecidable-instances -fallow-overlapping-instances #-} -- parser.hs: Copyright (C)2001,2002 Keean Schupke. -- -- Polymorphic monadic consumer based parser. module Lib.Monad.StateT where import Control.Monad hiding (guard) import Lib.Monad.MonadT import Lib.Monad.MonadState -- newtype StateT st m a = ST { runST :: st - m (st,a) } instance (MonadState st (StateT st m),Monad m) = Monad (StateT st m) where (ST m) = k = ST $ \s - do (s',a) - m s (\(ST x) - x) (k a) s' return a = ST $ \s - return (s,a) instance (MonadState st (StateT st m),MonadPlus m) = MonadPlus (StateT st m) where mzero = ST $ \_ - mzero (ST m) `mplus` (ST n) = ST $ \s - m s `mplus` n s instance (MonadState st (StateT st m),Monad m) = MonadT (StateT st) m where up m = ST $ \s - do a - m return (s,a) up1 f m = ST $ \s - do a - f (downST m s) return (s,a) up2 f m n = ST $ \s - do a - f (downST m s) (downST' n s) return (s,a) up3 f m n o = ST $ \s - do a - f (downST m s) (downST' n s) (downST' o s) return (s,a) down (ST m) = do (_,a) - m undefined return a downST :: Monad m = StateT st m a - (st - m a) downST m = \st - do (_,a) - runST m st return a downST' :: Monad m = (b - StateT st m a) - (st - b - m a) downST' m = \st b - do (_,a) - runST (m b) st return a instance (MonadState st (StateT st m),Monad m,Monad n,Runnable (st - m s) (st - n s)) = Runnable (StateT st m s) (st - n s) where run = run . downST instance (MonadState st (StateT st m),Monad m) = Runnable (StateT st m s) (st - m s) where run = downST instance Monad m = MonadState st (StateT st m) where update st = ST $ \s - return (st s,s) setState st = ST $ \_ - return (st,()) getState = ST $ \s - return (s,s) instance (MonadState st m,MonadT t m) = MonadState st (t m) where update = up . update setState = up . setState getState = up $ getState ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell] Re: Haskell DB bindings (was Re: ANN: HDBC (Haskell Database Connectivity)
John wrote: On 2006-01-14, Keean Schupke [EMAIL PROTECTED] wrote: Erm, has nobody replied to this yet? I want a robust interface, that uses bracket notation all the way down, so that any error is caught and resources are freed appropriately without the use of finalizers (which may not get run and lead to resource starvation - they are not reliable To be sure, your only failure situation in this case is if you're dealing with many connections *and* creating/destroying them frequently. Hopefully you wouldn't be. You could be using connection pooling in the database driver or ODBC layer... Here the minimal overhead of opening/closing allows you to use a bracket within each connection, rather than around the whole server. Besides which the goal is not just to be safe in practice, but to be theoretically safe in all circumstances. If you allow the programmer to shoot themselves in the foot, then they often will (for example memory management and buffer overflows)... Its no good to partly remove responsibility, as that makes bugs more likely not less likely (If the programmer has to deal with an opaque system with flaws, unless the programmer is highly aware of those flaws they will take no account of them in their coding). The only way you can give the programmer a genuine black box to play with, is if it is theoretically safe, then the programmer can (ab)use it how they wish without accidentally breaking the conditions of usage. Regards, Keean. ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Simple IO Regions
I really like this Oleg... I think I will use this myself as much as possible in future... As my DB code already uses bracket notation and an opaque/abstract DB handle type, it should be quite easy to incorporate this, without changing the interface... Cool! Regards, Keean. [EMAIL PROTECTED] wrote: This message shows a very simple implementation of Monadic Regions (for the particular case of IO and reading the file). The technique *statically* guarantees that neither a file handle nor any computation involving the handle can leak outside of the region that created it. Therefore, the handle can be safely closed (and its resources disposed of) whenever control leaves the corresponding 'withFile' block. Many handles can be open simultaneously, the type system enforces the proper nesting of their regions. The technique has no run-time overhead and induces no run-time errors. Unlike the previous implementation of monadic regions, only the basic extensions (higher-ranked types and one two-parameter type class) are used. No undecidable instances, no functional dependencies (let alone overlapping instances) are required. In fact, the implementation uses only one trivial typeclass and one trivial instance. Perhaps such an approach to File IO can be more widely used? It trivially generalizes to database IO and other kinds of IO. The motivation for monadic regions has been best explained by: Brandon Moore wrote on Haskell Cafe: I'm assuming you understand how the type on runST and the STRef operations ensure that, even though you *can* smuggle out an STRef in the result from runST, you will never be able to use it again. The idea was to do the equivalent thing with databases: use fancy types to ensure that handle can only be used inside to origination withDB or withCursor or whatever, and the bracketing function can release the resource on the way out, without worrying about it being used again. Benjamin Franksen wrote: I think this is an extremely good idea. I have been very frustrated with finalizers because of their limitations (can't rely on them being called at all), so have (reluctantly) been using the unsafe bracket version. Making it safe via a type system trick is really the way to go. Let us start with the tests {-# OPTIONS -fglasgow-exts #-} module IORegionsTest where import IORegions -- see below test0 = withFile /etc/motd (const $ return True) reader q = do c1 - qGetChar q c2 - qGetChar q return [c1,c2] test1 = withFile /etc/motd reader test1r = runIOM test1 = print Instead of handles, we have Qs -- marked handles. The are created by the function withFile and used similar to regular handles. A special IOM monad is a newtype away from the regular IO. The phantom type parameter of the IOM monad maintains the marks of the regions. *IORegionsTest :t reader reader :: (Monad (IOM marks), IORegions.IN mark marks) = Q mark - IOM marks [Char] the type of the reader shows that it takes a marked handle and yields a marked IO computation. The constraint IN assures that the computation must be marked with the mark of the handle. If we attempt to leak the handle: * test2 = withFile /tmp/i.hs (\q - return q) we get Inferred type is less polymorphic than expected Quantified type variable `mark' escapes In the second argument of `withFile', namely `(\ q - return q)' The following is OK: we perform the computation and return its result: test3 = withFile /etc/motd (\q - (qGetChar q)) If we attempt to return the unperformed computation itself: * test4 = withFile /tmp/i.hs (\q - return (qGetChar q)) we get Could not deduce (IORegions.IN mark marks1) from the context (IORegions.IN mark marks) arising from use of `qGetChar' at IORegionsTest.h... As we said earlier, more than one handle can be at play at the same time: reader2 q1 q2 = do c1 - qGetChar q1 c2 - qGetChar q2 return [c1,c2] test5 = withFile /etc/motd (\q1 - withFile /etc/motd (\q2 - reader2 q1 q2)) test5r = runIOM test5 = print Incidentally, the inferred type of reader2 is *IORegionsTest :t reader2 reader2 :: (Monad (IOM marks), IORegions.IN mark1 marks, IORegions.IN mark marks) = Q mark - Q mark1 - IOM marks [Char] Obviously, the resulting computation is marked with the marks of both argument handles. With two handles, we can actually return a handle -- provided we return an outermost handle from the innermost region (but not the other way around). For example, the following is wrong * test6 = withFile /etc/motd * (\q2 - * do *q' - withFile /etc/motd (\q - return q) *qGetChar q') but the following is OK: test7 = withFile /etc/motd (\q2 - do q' - withFile /etc/motd (\q - return q2)
[Haskell-cafe] Re: [Haskell] Simple IO Regions
Hi Oleg, Just made a few modifications and thought it might be useful to people. I have rewritten the functions as liftR and bracketR over a MonadIO monad interface (allowing monad-transformers to be used). This is now usable as Region library, as you can lift any arbitrary IO function into a Region. I don't think I have overlooked anything, and I think it is as safe as the original... but perhaps you would like to check for stupid mistakes... The exported interface is intended to be liftR, bracketR and runR. See attached MonadIORegion.hs... Regards, Keean. [EMAIL PROTECTED] wrote: This message shows a very simple implementation of Monadic Regions (for the particular case of IO and reading the file). The technique *statically* guarantees that neither a file handle nor any computation involving the handle can leak outside of the region that created it. Therefore, the handle can be safely closed (and its resources disposed of) whenever control leaves the corresponding 'withFile' block. Many handles can be open simultaneously, the type system enforces the proper nesting of their regions. The technique has no run-time overhead and induces no run-time errors. Unlike the previous implementation of monadic regions, only the basic extensions (higher-ranked types and one two-parameter type class) are used. No undecidable instances, no functional dependencies (let alone overlapping instances) are required. In fact, the implementation uses only one trivial typeclass and one trivial instance. {-# OPTIONS -fglasgow-exts #-} -- parser.hs: Copyright (C)2001,2002 Keean Schupke. -- -- Polymorphic monadic consumer based parser. module Main where import Control.Monad hiding (guard) import Control.Concurrent import Control.Exception as Exception import Lib.Monad.MonadT import IO import Network -- class Monad m = MonadIO m where ioBracket :: m a - (a - m b) - (a - m c) - m c liftIO :: IO a - m a instance MonadIO IO where ioBracket = Exception.bracket liftIO = id instance (MonadIO m,MonadT t m) = MonadIO (t m) where ioBracket = up3 ioBracket liftIO = up . liftIO -- newtype Region marks m a = Region { unRegion :: (m a) } deriving Monad class InRegion a b instance InRegion () b newtype Private mark h = Private h liftR :: (InRegion mark marks) = (h - m a) - Private mark h - Region marks m a liftR f (Private h) = Region $ f h bracketR :: MonadIO m = m h - (h - m b) - (forall mark . InRegion mark marks = Private mark h - Region marks m a) - Region marks m a bracketR f g h = Region $ ioBracket f g (\(x :: t) - unRegion $ h ((Private x) :: Private () t)) runR :: (forall mark . Region mark m a) - m a runR = unRegion test1 = bracketR (openFile /etc/services ReadMode) (hClose) (\f - do c1 - (liftR hGetChar) f c2 - (liftR hGetChar) f return [c1,c2]) -- test2 = bracketR (openFile /etc/services ReadMode) (hClose) (\f - return f) test3 = bracketR (openFile /etc/services ReadMode) (hClose) (\f - (liftR hGetChar) f) -- test4 = bracketR (openFile /etc/services ReadMode) (hClose) (\f - return ((liftR hGetChar) f)) -- test5 = bracketR (openFile /etc/services ReadMode) (hClose) (\f - f) main = do runR test1 = print -- runR test2 = print runR test3 = print -- runR test4 = print ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell] Re: ANN: HDBC (Haskell Database Connectivity)
Yes, I see... I edited it from the source code, which actually has the type: dbConnectWith :: VerifyTables t = (SqlHandle () - IO ()) - t - Query () - IO () dbConnectWith confn tabs query = confn (do { _ - runST (do verifyTables tabs ; query) 0; return () }) I obviously did not think hard enough about the changes I was making for readability... Keean Benjamin Franksen wrote: On Monday 09 January 2006 10:03, Axel Simon wrote: On Sun, 2006-01-08 at 14:51 +, Keean Schupke wrote: My solution to this when developing a database library for my own use was to define the API in a bracket notation style, and only provide safe functions. The idea is that the function obtains the resource, calls a function passed as an argument, then frees the resource, so all resouces are guaranteed to be freed in the correct order... for example: dbConnectWith :: DbName - (DbHandle - IO Result) - Result dbConnectWith name workFn = do handle - dbConnectTo name workFn handle `finally` dbDisconnect handle In this way you avoid finalizers... and everthing is safe providing you only export the with style functions from the library... Here's an example from the library, the connect function: I suppose you meant to write result rather than Result. This style of functions is only safe if the user ensures that DbHandle is never returned as part of the result. You should have that in your documentation. I wanted to mention this too, but you were quicker ;) As far as I can tell, the only general solution is to use finalizers and, if you really need to enforce a sequence of finialization, touchForeignPtr. Repeat: touchForeignPtr can NOT be used to enforce finalization order. A practical issue with touchForeignPtr is that it cannot be conveniently called from another finalizer, since the latter live in C. What do you mean live in C? Can't or shouldn't finalizers be written in Haskell, too? Ben ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Haskell DB bindings (was Re: ANN: HDBC (Haskell Database Connectivity)
Erm, has nobody replied to this yet? I want a robust interface, that uses bracket notation all the way down, so that any error is caught and resources are freed appropriately without the use of finalizers (which may not get run and lead to resource starvation - they are not reliable if dealing with many connections, unless you start forcing garbage collections). I want a simple interface (as few functions as possible to do the job) and robust exception handling. I certainly like the idea of using runST to encapsulate the DbHandle... and infact the DB code I have does this, but not in a systematic way... I guess really all allocated handles that are passed to user defined functions need to be protected in this way. The code I wrote is really to support a relational algebra layer over the top... When I developed this there were no database drivers that worked under linux, as HSQL only supported ODBC under windows, so I developed an ODBC specific layer myself tested with unixODBC and iODBC. So IMHO, braket notation, STRef encapsulation, no finalizers, lots of exception handling, minimal interface. I would sacrifice some speed for simplicity of interface... Keean Krasimir Angelov wrote: There are three active database libraries: HDBC, HSQL and Takusen. It is quite disappointing from my point of view. Recently there was the same situation with the GUI libraires. The Haskell Community is quite small to waste efforts, developing different libraries for the same things. When I started with HSQL there were only two database libraries: HaSQL for ODBC and libpq for PostgreSQL. They both are dead, I think. I decided that it is useful to have one abstract API that can cover all database bindings. I imagine something like JDBC, ADO or DBI for Haskell. If you guys would like this to happen then lets discuss what we want. I would be happy to work on single project that can satisfy all needs. Cheers, Krasimir 2006/1/10, Tim Docker [EMAIL PROTECTED]: [EMAIL PROTECTED] wrote: Incidentally, the difficulty with finalizers was precisely the argument for using enumerators rather than cursors in database APIs. Takusen has implemented that idea; takusen currently supports Sqlite, PostgreSQL and Oracle, has a test suite. Its performance test shows that takusen can retrieve 2 million rows from a table without running out of memory. The differences between HDBC and HSQL have been recently discussed. Where does Takusen fit into this picture? From the above, it sounds like it has quite a different API. Are all 3 of these actively maintained? As someone who may wish to construct a haskell db binding for a new db, it's not clear to which API it should conform. Sometimes choice is a burden... Tim ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Re: ANN: HDBC (Haskell Database Connectivity)
My solution to this when developing a database library for my own use was to define the API in a bracket notation style, and only provide safe functions. The idea is that the function obtains the resource, calls a function passed as an argument, then frees the resource, so all resouces are guaranteed to be freed in the correct order... for example: dbConnectWith :: DbName - (DbHandle - IO Result) - Result dbConnectWith name workFn = do handle - dbConnectTo name workFn handle `finally` dbDisconnect handle In this way you avoid finalizers... and everthing is safe providing you only export the with style functions from the library... Here's an example from the library, the connect function: safeConnect :: (SqlIO m,SqlIfIO m,MonadIO m,MonadPlus m) = SqlDbc - OdbcConnection - (SqlDbc - m a) - m a safeConnect dbc connection doWith = ioBracket ( ioBracket (ioNewCStringLen (odbcDsn connection)) (\(dsnS,_) - ioFree dsnS) (\(dsnS,dsnL) - ioBracket (ioNewCStringLen (odbcUid connection)) (\(uidS,_) - ioFree uidS) (\(uidS,uidL) - ioBracket (ioNewCStringLen (odbcAuth connection)) (\(authS,_) - ioFree authS) (\(authS,authL) - do status - ioSqlConnect dbc dsnS (fromIntegral dsnL) uidS (fromIntegral uidL) authS (fromIntegral authL) ioIfFail status (\s - fail ((showString Bad status returned by sqlConnect ( . shows s) ))) (\_ - ioSqlDisconnect dbc) (\_ - doWith dbc) Keean Chris Kuklewicz wrote: Benjamin Franksen wrote: On Wednesday 04 January 2006 20:13, John Goerzen wrote: Well, yes and no. It would be impossible to garbage collect (and thus finalize) any object for which references to it still exist. Statement handles in HDBC maintain references to the database handle pointers, either directly or indirectly, so I can't see how it is possible for a database handle to be finalized before the statement handle in this situation. Hi John, I fear it /is/ possible. This is a very unfortunate situation and one I had quite some difficulties to understand, when Simon Marlow explained it to me. The problem is that finalization of the statement handle might be delayed indefinitely. The data dependencies between statement and connection handle only ensures that whenever the statement handle is alive, then too is the connection handle. But it does not say anything about what happens in which order after /both/ are dead (garbage). As soon as the connection handle to garbage, too, bothe handles can be finalized in /any/ order. As I pointed out before, this is a very bad thing, because it makes finalizers a whole lot less useful than they could be if an order between finalizations could be specified (directly or indirectly). The arguments against such a solution are mostly: (1) it is difficult to implement efficienty and (2) the programmer could accidentally cause finalizer deadlocks by specifying circular dependencies. Ben This is also mentioned in the documentation: http://www.haskell.org/ghc/docs/6.4.1/html/libraries/base/Foreign-ForeignPtr.html#v%3AtouchForeignPtr touchForeignPtr :: ForeignPtr a - IO () This function ensures that the foreign object in question is alive at the given place in the sequence of IO actions. In particular withForeignPtr does a touchForeignPtr after it executes the user action. Note that this function should not be used to express liveness dependencies between ForeignPtrs. For example, if the finalizer for a ForeignPtr F1 calls touchForeignPtr on a second ForeignPtr F2, then the only guarantee is that the finalizer for F2 is never started before the finalizer for F1. They might be started together if for example both F1 and F2 are otherwise unreachable, and in that case the scheduler might end up running the finalizer for F2 first. In general, it is not recommended to use finalizers on separate objects with ordering constraints between them. To express the ordering robustly requires explicit synchronisation using MVars between the finalizers, but even then the runtime sometimes runs multiple finalizers sequentially in a single thread (for performance reasons), so synchronisation between finalizers could result in artificial deadlock. ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: GHCI and archive libraries.
Thaks guys... I realise it is a simple matter of unpacking the object files, however when using ghci for prototyping, it can be more convenient to have all the '.o's packed into a '.a'. As it is a simple matter to extract the .o files from the .a, I would have thought a fairly small change to the ghci code would have enabled using archive libraries. I think this change would aid usability. I don't know the ghci code at all, so it would take me a long time to make this change, as I would first have to understand the existing code. I was wondering if anyone familier with the ghci code could add archive library support? I suppose as a work around I could write a wrapper for ghci that extracts the .o files from the .a to a temp directory, and then calls ghci with the .o files on the command line. Regards, Keean. Sven Panne wrote: Am Samstag, 3. Dezember 2005 15:17 schrieb Lennart Augustsson: And on many platforms (well, at least a few years ago) a shared library doesn't have to be PIC. The dynamic loader can do relocation when it loads the file. (Then it can't be shared.) But this was a few years ago on Solaris and BSDs, it could be different now. After a quick look this seems to be the case on current x86 Linux systems, too: Real shared libraries consist of PIC to enhance sharing code at runtime, but nevertheless the dynamic loader seems to be able to load and relocate non-PIC, at the cost of less sharing, but often slightly better code quality. So the mentioned repacking of a static library into a partially linked object file might work for most common platforms. Cheers, S. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
GHCI and archive libraries.
GHCI does not load archive libraries. Is it possible (easy?) to get it to load (.a) archive libraries as well as .o and .so files? The problem is some optimized cblas libraries are not available as shared libraries due to the performace loss. Regards, Keean. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Records (was Re: [Haskell] Improvements to GHC)
you can always do: case (field1 record,field2 record, field3 record ...) of (pat1,pat2,pat3) - _ - Which lets you pattern match on fields independantly of their position in the record. Keean. David Roundy wrote: On Wed, Nov 23, 2005 at 02:58:43PM +0100, Wolfgang Jeltsch wrote: Am Mittwoch, 23. November 2005 14:22 schrieb David Roundy: On Tue, Nov 22, 2005 at 02:32:47PM +, Rob Ennals wrote: [...] 7. Unordered records: yep (if I understand the problem correctly) ... You can just omit the data constructors from the module's export list. Yes, you can do that if you don't want to allow pattern matching. That's an acceptable solution for truly exported (i.e. opaque) data, but for internal data structures I would like to allow pattern matching without allowing positional matching (or constructing). Too many times I've had to go through the entire code adding an extra _ to each pattern match, and each time there's a possibility you'll add it in the wrong spot. I could do this with coding guidelines, but I'd prefer to have the compiler enforce this. ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
[Haskell-cafe] Re: Records vs HList
David Menendez wrote: Keean Schupke writes: HList can do O(log n) by the way, if the labels have order, you can implement a binary search tree of labels (Of course all the accessor functions would need to be rewritten). The idea of writing a type-level balanced binary search tree fills me with an uncertain mixture of excitement and dread. Particularly if you want to be able to compare records for equality. Hmm... You have to write and define what you mean by equality for normal HList records anyway. As you need to ignore the order of elements the equality test is effectively: a == b if (a `subset` b) and (b `subset` a) The test for a subset b tests if each element in a exists in b. With an ordered tree, the labels must be in the same order, so the equality just has to compare elements is a consistant (say pre-order) way. In the end HList records were written as they are for clarity in the paper, and not really as a number-crunching implementation. I find them fast enough for database work, where the records represent the query (in terms of projections) and the result table in a type safe way... Infact my simple DB library goes quite a way beyond what HaskellDB can do, mainy due to the complex type-mechanics being hidden inside the HList/record library. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Re: Records vs HList
David Menendez wrote: Keean Schupke writes: David Menendez wrote: Chris Kuklewicz writes: Would the record system describe at http://lambda-the-ultimate.org/node/view/1119 also be convertable into System Fw, GHC's existing, strongly-typeed intermediate language. ? Probably. Daan's current implementation uses MLF, which I believe is system F implemented for ML. (We're talking about the system in Daan Leijen's paper, Extensible Records With Scoped Labels. Good stuff.) You can change the project and update operators in the HList library to behave in exactly this way. At the moment they are constrained to not allow multiple identical labels in records. If this kind of access is considered useful, I can add it to the HList distribution. This is true. I've implemented a small subset of HList that's able to emulate Daan's three record operators using only fundeps and undecidable instances. *Main let r = foo .=. Bar .*. emptyRecord *Main r Record{foo=Bar} *Main let r2 = foo .=. () .*. r *Main r2 Record{foo=(),foo=Bar} *Main r2 .!. foo () *Main (r2 .-. foo) .!. foo Bar (This is actually *more* powerful than the system described in Daan's paper, because labels are first class.) While this is a testament to the power of Haskell's extended type-class system, I'm not sure that it can replace a dedicated record system. In his paper, Daan describes how to implement the records such that field lookups take O(log n) or even O(1) time. HList can't do better than O(n). Of course, in the absence of a powerful record system, HList is the way to go. Rather than decide on a new record system sight unseen, let's implement them using HList and see how they feel.E Exactly! I like the idea of being able to construct and modify the semantics of a record system (and with the stuff in the OOHaskell paper you can play with Object systems in the same way). The important point with HLists is not that record syntax should not be added to Haskell, but that we can translate it to the existing type system with no conflicts. (ie the type system does not need to be extended there just needs to be some syntax, with an optimised implementation) HList can do O(log n) by the way, if the labels have order, you can implement a binary search tree of labels (Of course all the accessor functions would need to be rewritten). I wonder if some syntactic support for label creation would make things nicer. Actually one really useful change I would like would be to define type class functions over all tuples, that way you could write O(1) accessor functions on tuples using peano number indexes. class TupleIdx u i t | u i - t where idx :: u - i - t instance (a,b) HNil a where (a,_) _ = a instance (a,b) (HSucc HNil) b where (_,b) _ = b instance (a,b,c) HNil a where (a,_,_) = a instance (a,b,c) (HSucc HNil) b where (_,b,_) = b instance (a,b,c) (HSucc (HSucc HNil)) c where (_,_,c) = c etc... However I haven't thought very hard about how to represent the complete (infinite) set of instances, but using this you can write products of tuples, and create records with O(1) access times from a pair of tuples. Keean ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Existential quantification of environments.
If I have a function: f x y = add x y and I want to type the function in isolation, then the type of 'add' is essentially carried in the environment... Lets say I want to make this type explicit in the type signature (where f is valid for any a where there is an add function on a - ignoring the class that Haskell would require for the overloading): add :: Int - Int - Int add :: Float - Float - Float f :: forall a . exists (add :: a - a - a) = a - a - a or a step further: class Add a where add :: a - a - a instance Add Int where ... instance Add Float where ... f :: forall a . Add a = a - a - a This seems to suggest: Add a == exists (add :: a - a - a) Does this seem in any way right? It seems that the definition of 'f' does require the existance of 'add'. That is the definition is valid iff there exists a function called 'add' of the correct type. Also doesn't the existential quantifier stop you looking inside 'add' - obviously you cannot inspect the definition as it may not be defined (yet?), but presumably you can still apply 'add'. Regards, Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] records proposals list
The HList code does not need overlapping-instances, however it does use undecidable instances. This is not however bad like overlapping instances is. Overlapping instances can break module independance (as in defining a new instance can change the meaning of an existing class in modules that are already compiled). Undecidable instances merely means the compiler is not capable of proving that the constraints terminate. In the case of an HList they obviously do (where the constraint recursion is structurally over the length of a list termination is obvious). This is more a weakness in the compiler rather than some problem with the HList code. Keean. Wolfgang Jeltsch wrote: Am Dienstag, 22. November 2005 07:33 schrieb David Menendez: Keean Schupke writes: Haskell already has static records (in H98) Dynamic records are addressed by the HList library, which uses extensions already present in GHC and Hugs (namely Multi-parameter type-classes and function-dependancies). Is this the case? Every implementation of HList that I've seen also uses overlapping and undecidable instances. The paper about HList I have seen does explicitely say that the authors were finally able to avoid using overlapping instances. I don't know about undecidable instances but I thought (and hope very much) that they don't need them too. Best wishes, Wolfgang ___ 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
Re: [Haskell-cafe] records proposals list
My mistake, what you want is: ( mything .=. something .*. value .=. (27::Int) .*. logic .=. True .*. HNil ) Admittedly the label creation would benefit from some syntactic sugar to reduce typing... Keean. Bulat Ziganshin wrote: Hello Keean, Monday, November 21, 2005, 6:56:06 PM, you wrote: KS So you can do this now... with reasonable syntax, for example to KS create an extensible record KS (some thing .*. (27 :: Int) .*. True .*. HNil) KS is a statically typed anonymous record. it is not record, but heterogenous list, in my feel. record must be indexed by field name, not by type name or position ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] records proposals list
Just a follow up to my last post ... The HList paper also presents a way of removing overlapping instances from _any_ class. So infact support for overlapping instances is no longer required - and this removes all the messy problems with overlapping instances and functional dependancies. The current HList source distribution runs in hugs with -98 +o only because of lazyness on out part. All the occurances of overlapping instances can (will?) be removed from the source if it becomes an important issue (most of them are in auxilliary definitions that are not in the paper, like Show for HList. If you program in the completely non overlapping instances model, then compiler support for deriving TTypeable would be nice, or compiler support for a type level equality constraint (TypeEq could become a built-in). But just to make it clear - compiler support for this is not necessary, you just define instances of TTypeable for all your datatypes. There is a template-haskell library that can automatically derive TTypeable for any datatype as well. Keean. David Menendez wrote: Keean Schupke writes: Haskell already has static records (in H98) Dynamic records are addressed by the HList library, which uses extensions already present in GHC and Hugs (namely Multi-parameter type-classes and function-dependancies). Is this the case? Every implementation of HList that I've seen also uses overlapping and undecidable instances. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Records
Just my 2p worth... If I were designing a language I would not have used the '.' like Haskell does. One problem is that ascii does not support enough symbols (Hmm, PL1 here we come). I guess my vote would go to keeping the '.' as is to not break existing programs, and using a different symbol for record access and qualified names... however '.' works well for DNS names: [EMAIL PROTECTED] -- function composition (people are used to reading the @ backwards due to emails) M.f -- qualified naming... f?f -- record access... really needs more symbols... of course the problem then becomes entering them on a normal keyboard. Keean. Ketil Malde wrote: Cale Gibbard [EMAIL PROTECTED] writes: This really isn't so bad in practice though. I've certainly never been confused by it. Well, what can I say? Good for you? You'd have to go out of your way to construct a situation in which it's potentially confusing No. There are much more important issues to deal with than this, really. Like inventing as many new and wonderful symbolic operators as possible! Hey, why not allow quoted function names? So that I can defined a function f different from f ? Or differentiate (+4) from completely different (+ 4), ( +4) and ( + 4) which *obviously* are entirely differen things? might be relevant in the IOHCC, but not in ordinary programming. So why not go for the Obfuscated Language Design Contest instead? In a sane language, small amounts of whitespace sensitivity are going to be around no matter what you do. And if you already are using whitespace to separate words, surely the logical (not to mention aesthetical) way forward would be to introduce evene more whitespace sensitivity - here is the Holy Grail http://compsoc.dur.ac.uk/whitespace/index.php I don't understand why this isn't obvious to people who generally appear fairly bright, but: introducing extension that turns working programs into non-working ones is generally a bad idea. Having it be due to spacing habits around symbolic operators is worse. That spacing changes suddenly starts bringing very complex language extensions into the picture, with an associated heap of incomprehensible error messages is *not* a nice thing for anybody - except, perhaps, the two academics who wrote the paper, and the three academics who read it. /rant Okay, I'm being unfair here. Haskell is an academic language, its primary purpose is to produce papers, not software. And as a mere programmer, I'm in a minority. I think Haskell is really cool, but I don't really belong here, and I realize of course that my voice isn't going to carry a lot of weight. But IF there is a desire for Haskell to be used for Real Work, I think there should be a certain degree of stability. Taking the function composition operator and turning it into record selection -- depending on spacing, of course -- is, IMO, madness. But good luck on those papers, and see you later, probably on the Clean mailing lists. -k ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Existential quantification of environments.
Excellent link thanks! Not quite what I was thinking of - but definitely related. I'll give it a read and see if they want to existentially quantify environments... Keean. Adrian Hey wrote: On Tuesday 22 Nov 2005 10:39 am, Keean Schupke wrote: If I have a function: f x y = add x y and I want to type the function in isolation, then the type of 'add' is essentially carried in the environment... I am no expert in type theory so I'm probably about to get way out of my depth, but isn't this what principal typings are all about (as distinct from principal types). Maybe a look at type system CT would be useful too. http://www2.dcc.ufmg.br/~camarao/CT/ Regards -- Adrian Hey ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: Pickling HList
This function is already in the HList library (well early versions anyway)... I dont think this is in the current distribution. Its a generic constructor wrapper. For example: hMarkAll Just hlist class HList l = HMarkAll c l m | c l - m where hMarkAll :: (forall a . a - c a) - l - m instance HMarkAll c HNil HNil where hMarkAll _ _ = HNil instance HMarkAll c l m = HMarkAll c (HCons e l) (HCons (c e) m) where hMarkAll c (HCons e l) = HCons (c e) (hMarkAll c l) Keean. Joel Reymont wrote: Credit goes to Cale: class (HList l, HList p) = HLPU p l | p - l, l - p where puHList :: p - PU l instance HLPU HNil HNil where puHList HNil = lift HNil instance (HList l, HLPU p l) = HLPU (HCons (PU e) p) (HCons e l) where puHList (HCons pe l) = wrap (\(a, b) - HCons a b, \(HCons a b) - (a, b)) (pair pe (puHList l)) On Nov 10, 2005, at 2:04 PM, Joel Reymont wrote: Folks, I'm having trouble creating a pickler for HLists and would appreciate a solution. The code for (HCons e HNil) works fine but I get an error trying to implement puHList for (HCons e l) where l is supposed to be (HCons e ...), i.e. another HList. Bar.hs:21:37: Couldn't match the rigid variable e' against PU e' `e' is bound by the instance declaration at Bar.hs:17:0 Expected type: HCons (PU e) l Inferred type: HCons e l In the first argument of puHList', namely l' In the second argument of pair', namely (puHList l)' Failed, modules loaded: none. -- http://wagerlabs.com/ ___ 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
Re: [Haskell-cafe] Existential quantification of environments.
Wolfgang Jeltsch wrote: This seems to suggest: Add a == exists (add :: a - a - a) Doesn't exists normally quantify over types and not over values? It is quantifying over types, it is saying there exists a type a - a - a that has at least one value we will call add... I think the important point is that the existential is a pair of (proof, proposition) which through curry-howard-isomorphism is (value in set, set). Here we are saying that there is a set of functions with the type a - a - a ... for the existential to be satisfied there must be one called add. Consider this as an assumption placed on the environment by the function. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: Pickling HList
That all depends... In theory all the HList stuff happens at compile time, and what you are left with is normal function application... Of course compilers arn't that good yet, but as a reasonable idea, consider just that value level... Most of the extra work is the packing/unpacking of pairs (,). I have used HList for database schemas like the Cow example database (see attached) with no problems. The DB code includes code to generate the database from this Schema so is doesn't need to be entered twice, and it also typechecks the database against the schema in a one-way extensional manner on program start. The performance of the DB app is good, better than with scripting languages like perl/python, and type-safe. This code uses records made from HLists (see the paper for examples). Keean. Joel Reymont wrote: Keean, I sort of gave up on HList for the time being since I found easier ways to solve my problem. Mainly, I could not estimate the impact it would have on run-time performance of my code and GHC not being able to compile the code was not a good indication. Simon PJ fixed that error since. My idea was to, basically, create my own record sans labels. I wanted to specify picklers and default values for each field instead. I have over 250 records, though, and some have over 10 fields. There is a lot of sharing of fields between the records but I still think this is too much for GHC to handle. Can you venture a guess on runtime performance of such code? Thanks, Joel On Nov 22, 2005, at 4:07 PM, Keean Schupke wrote: hMarkAll Just hlist class HList l = HMarkAll c l m | c l - m where hMarkAll :: (forall a . a - c a) - l - m instance HMarkAll c HNil HNil where hMarkAll _ _ = HNil instance HMarkAll c l m = HMarkAll c (HCons e l) (HCons (c e) m) where hMarkAll c (HCons e l) = HCons (c e) (hMarkAll c l) -- http://wagerlabs.com/ {-# OPTIONS -fglasgow-exts #-} {-# OPTIONS -fallow-overlapping-instances #-} {-# OPTIONS -fallow-undecidable-instances #-} module Lib.Relational.FamDb where import Char import Lib.ODBC.Types import Lib.TIR.HList import Lib.TIR.HTypeGHC import Lib.TIR.HRecord import Lib.Relational.Types as SQL --- -- Foot and Mouth Database famdb :: (FarmerTable:*:FarmTable:*:AnimalTable:*:ContaminatedTable:*: HNil) famdb = (farmerTable.*.farmTable.*.animalTable.*.contaminatedTable.*.HNil) --- -- Domains newtype DFarmerId = DFarmerId Int deriving (Show,Eq,ToSqlType SqlInteger,FromSqlType SqlInteger) newtype DFarmerName = DFarmerName String deriving (Show,Eq,ToSqlType SqlVarchar,FromSqlType SqlVarchar) newtype DFarmId = DFarmId Int deriving (Show,Eq,ToSqlType SqlInteger,FromSqlType SqlInteger) newtype DFarmName = DFarmName String deriving (Show,Eq,ToSqlType SqlVarchar,FromSqlType SqlVarchar) newtype DFarmCounty = DFarmCounty String deriving (Show,Eq,ToSqlType SqlVarchar,FromSqlType SqlVarchar) newtype DAnimalId = DAnimalId Int deriving (Show,Eq,ToSqlType SqlInteger,FromSqlType SqlInteger) newtype DAnimalName = DAnimalName String deriving (Show,Eq,ToSqlType SqlVarchar,FromSqlType SqlVarchar) data DAnimalType = Cow | Sheep deriving (Show,Eq) newtype DAnimalPrice = DAnimalPrice Float deriving (Show,Eq,ToSqlType SqlNumeric,FromSqlType SqlNumeric) data DCntdType = BSE | FM deriving (Show,Eq) instance FromSqlType SqlVarchar DAnimalType where fromSqlType _ s = case (map toLower s) of cow - Just Cow sheep - Just Sheep _ - Nothing instance ToSqlType SqlVarchar DAnimalType where toSqlType Cow = SqlTyped (SqlExpressionConst $ sqlShow cow ) toSqlType Sheep = SqlTyped (SqlExpressionConst $ sqlShow sheep ) instance FromSqlType SqlVarchar DCntdType where fromSqlType _ s = case (map toLower s) of bse - Just BSE fm - Just FM _ - Nothing instance ToSqlType SqlVarchar DCntdType where toSqlType BSE = SqlTyped (SqlExpressionConst $ sqlShow BSE ) toSqlType FM = SqlTyped (SqlExpressionConst $ sqlShow FM ) --- -- Farmer table data FarmerId = FarmerId deriving Show data FarmerName = FarmerName deriving Show type FarmerTable = Table ( FarmerId :=: Attribute DFarmerId SqlInteger :*: FarmerName :=: Attribute DFarmerName SqlVarchar :*: HNil) farmerTable :: FarmerTable farmerTable = newTable Farmer ( FarmerId .=. Attribute (attr { attrName=farmerid, attrType=SERIAL }) .*. FarmerName .=. Attribute (attr { attrName=name, attrSize=20 }) .*. HNil) --- -- Farm table data FarmId = FarmId deriving Show data FarmName = FarmName deriving Show data FarmCounty = FarmCounty deriving
Re: [Haskell-cafe] records proposals list
Hi, Haskell already has static records (in H98) Dynamic records are addressed by the HList library, which uses extensions already present in GHC and Hugs (namely Multi-parameter type-classes and function-dependancies). So you can do this now... with reasonable syntax, for example to create an extensible record (some thing .*. (27 :: Int) .*. True .*. HNil) is a statically typed anonymous record. In other words there is no need for any more extensions to GHC or Hugs to implement Records (although having a type-level type-equality constaint would simplify the internal implementation of the library)... For details see the HList paper: http://homepages.cwi.nl/~ralf/HList/ Regards, Keean. Bulat Ziganshin wrote: Hello Haskell, can anyone write at least the list of record proposals for Haskell? or, even better, comment about pros and contras for each proposal? ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Spurious program crashes
One thing, which I am sure you must have got right, but which burned me, is that you must explicitly free enitities created by FFI calls. For example network sockets exist outside of the haskell runtime, and are not free'd automatically when a haskell thread is killed, you need an explicit exception handler to close the handle... They may eventually be garbage collected - but your application may run out of resources before this happens. Keean. Joel Reymont wrote: Maybe one of the Simons can comment on this. I distinctly remember trying the mdo approach to kill the other thread and getting burned by that. Don't know why I forgot to mention it. On Nov 17, 2005, at 2:03 PM, Sebastian Sylvan wrote: What I do remember is that the timeout and parIO functions in the concurrent programming papers I found were NOT correct. killThread did NOT behave as expected when I killed an already killed thread. I tried multiple tricks here (including some which required recursive do-notation) to try to get the parIO function to only kill the *other* thread. This could be done by having the two spawned threads take their computations in an MVar along with the threadID of the other thread. -- http://wagerlabs.com/ ___ 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
Re: [Haskell-cafe] Records (was Re: [Haskell] Improvements to GHC)
You can change the project and update operators in the HList library to behave in exactly this way. At the moment they are constrained to not allow multiple identical labels in records. If this kind of access is considered useful, I can add it to the HList distribution. Keean. David Menendez wrote: Chris Kuklewicz writes: Would the record system describe at http://lambda-the-ultimate.org/node/view/1119 also be convertable into System Fw, GHC's existing, strongly-typeed intermediate language. ? Probably. Daan's current implementation uses MLF, which I believe is system F implemented for ML. (We're talking about the system in Daan Leijen's paper, Extensible Records With Scoped Labels. Good stuff.) ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Records (was Re: [Haskell] Improvements to GHC)
Can this not be done with the HList code? I am pretty sure you should be able to map projections over HLists of HLists... (although the HList generic map is a bit ugly, requiring instances of the Apply class). Actually you should look in the OOHaskell paper (if you haven't already) where it discusses using narrow to allow homogeneous lists to be projected from heterogeneous ones... Keean. John Meacham wrote: another thing is that for any record syntax, we would want higher order versions of the selection, setting, and updating routines. A quick perusal of my source code shows over half my uses of record selectors are in a higher order fashion. (which need to be generated with DrIFT with the current syntax) I mean something like map (.foo) xs to pull all the 'foo' fields out of xs. (using made up syntax) or map (foo_s 3) xs to set all the foo fields to 3. (using DrIFT syntax) John ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Interactive Haskell and hs-plugins
The symbols must be exported from the main program... I think you can pass the linker an option to force it to export symbols. Keean. Fraser Wilson wrote: Hi there, I would like to use evaluate arbitrary expressions in the context of a mixed-language (Ada, Haskell and about twelve lines of C glue) applications. Is it possible to use dynload from hs-plugins to load a module that references symbols in the loading program? For example, the application contains a Haskell module that looks a bit like this: module TestKeys.NamedObject where tt :: Int tt = 2 I want the application to be able to offer the following sort of interaction: haskell tt 2 haskell But what actually happens is this: haskell tt test_haskell3: /tmp/MDnum15633.o: unknown symbol `TestKeysziNamedObject_tt_closure' test_haskell3: user error (resolveObjs failed with False) Compiling Haskell code in advance works (i.e. if I create and compile a module that evalutes tt and link it in, everything runs fine). This is how I try to evaluate the expression: evaluate :: String - IO () evaluate = return () evaluate e = do writeFile temp.hs fileContents status - makeWith LeanderStub.hs temp.hs [-c] case status of MakeSuccess code path - loadAndEval path MakeFailure error - print error where fileContents = module Temp where\n\ \ result = ++ e ++ \n loadAndEval :: FilePath - IO () loadAndEval path = do mv - dynload path [] [] result case mv of LoadFailure msg - print msg LoadSuccess _ v - putStrLn v LeanderStub.hs is a module containing the necessary imports for the expression to evaluate in the right context. I was hoping that passing -c to makeWith would create an object file whose missing dependencies would be resolved when it was loaded into an application which contained them. Is this a dumb expectation? The alternative -- linking to the entire application for each expression evaluated -- seems a bit over the top, and I can't see how state would be maintained. I originally used unsafeEval_, but this has the same problem. I can't help but think that this must have been done before. Any advice? If you know Guile, then the equivalent of gh_repl is what I'm really after. cheers, Fraser. ___ 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
Re: [Haskell-cafe] Re: Network parsing and parsec
Andrew Pimlott wrote: On Tue, Sep 20, 2005 at 03:01:32PM +0100, Keean Schupke wrote: (see attachment for files) You didn't include all the used libraries (MonadControl, MonadState). Andrew Oops, here they are (it was extracted from a larger project), sorry about that... (Have posted this back to the mailing list incase anyone else is tying to use the libraries I posted) Regards, keean. parser.tgz Description: application/compressed-tar ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: Network parsing and parsec
John Goerzen wrote: On 2005-09-15, Adam Turoff [EMAIL PROTECTED] wrote: On 9/15/05, John Goerzen [EMAIL PROTECTED] wrote: So, to make that approach work, I would really need to do a lot of work outside of Parsec -- the stuff that I really want to use Parsec for, I think. Well, you do have a state monad to work with. Why not just stuff the number 305 into your state, keep reading until you've read 305 bytes (decrementing the count as you read), and return the 305-byte string as your result for this parser? When you resume, you should be ready to parse the next very token after the 305-byte string. It's unclear to me exactly how to mix the IO monad with Parsec. It doesn't really seem to be doable. Not to mention that if hGetContents is used, the Handle has to be put into non-buffering mode, which means one syscall per character read. Terribly slow. Does it? I didn't think so ... Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: Network parsing and parsec
You may like my parser transformer then (based on the efficent backtracking parser paper, I believe by Ralf Heinze - uses endofunctor and continuation passing - Its a long time since I tested it but I think it holds its own against Parsec, without requiring the extra return types). -- parser.hs: Copyright (C)2001,2002 Keean Schupke. -- -- Polymorphic monadic consumer based parser. module Lib.Monad.ParserT(ParserT(..)) where import Control.Monad hiding (guard) import Control.Monad.Error import Lib.Monad.MonadT import Lib.Monad.MonadState import Lib.Monad.MonadParser import Lib.Monad.MonadControl import Lib.Arrow.Runnable -- -- An continuation passing endomorphic parser type Cps a r = (a - r) - r type Endo r = r - r newtype ParserT r tok m a = PT (Cps a ([tok] - Endo (m r))) instance Monad m = Functor (ParserT r tok m) where fmap g (PT m) = PT $ \k - m (\a s f - k (g a) s f) instance Monad m = Monad (ParserT r tok m) where {-# INLINE return #-} return a = PT $ \k - k a {-# INLINE (=) #-} (PT m) = f = PT $ \k - m (\a - (\(PT x) - x) (f a) k) instance Monad m = MonadPlus (ParserT r tok m) where {-# INLINE mzero #-} mzero = PT $ \_ _ f - f {-# INLINE mplus #-} mplus (PT m) (PT n) = PT $ \k s - m k s . n k s instance MonadPlus m = MonadT (ParserT r tok) m where {-# INLINE up #-} up m = PT $ \k s f - (m = \a - k a s mzero) `mplus` f {-# INLINE down #-} down = undefined instance (MonadPlus m,MonadT (ParserT r tok) m,Runnable ([tok] - m ([tok],r)) ([tok] - n ([tok],r))) = Runnable (ParserT ([tok],r) tok m r) ([tok] - n ([tok],r)) where run = run . (\(PT m) t - m (\a t' f - return (t',a) `mplus` f) t mzero) instance (MonadPlus m,MonadT (ParserT r tok) m) = Runnable (ParserT ([tok],r) tok m r) ([tok] - m ([tok],r)) where run = (\(PT m) t - m (\a t' f - return (t',a) `mplus` f) t mzero) instance Monad m = MonadState [tok] (ParserT r tok m) where {-# INLINE update #-} update st = PT $ \k s - k s ((st s) `asTypeOf` s) setState st = PT $ \k _ - k () st getState = PT $ \k s - k s s instance Monad m = MonadParser tok (ParserT r tok m) where {-# INLINE item #-} item = PT $ \k s - case s of [] - id (a:x) - k a x instance (MonadPlus (t m),MonadParser tok m,MonadT t m) = MonadParser tok (t m) where item = up item instance Monad m = MonadControl (ParserT r tok m) where {-# INLINE once #-} once (PT m) = PT $ \k s f - m (\a s' _ - k a s' f) s f Regards, Keean. John Goerzen wrote: On 2005-09-16, Andrew Pimlott [EMAIL PROTECTED] wrote: On Thu, Sep 15, 2005 at 06:11:58PM -0700, Andrew Pimlott wrote: I don't see why this would be more error-prone than any other approach. Hmm... I take that back. I don't know anything about the IMAP protocol, but after imagining for a few moments what it might be like, I can see how it could be more difficult than my example. The user state of the parser might help you... Hmm, can you elaborate on that? Basically, I *really* want to get away frmo having to use hGetContents. It is just not at all friendly for an interactive netwrk protocol. If I were just streaming a large file from an FTP server, it would be fine, but even using it to begin with involves using Handles in a nonstandard way (since there must be a separate Handle for writing, since hGetContents sents the Handle to be half-closed) that is apparently not well-supported. -- John ___ 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
Re: [Haskell-cafe] Re: Network parsing and parsec
Here's some useful definitions to go with that... module Lib.Parser.Parser(Parser,when,unless,guard,(|),opt,many,many1,sepBy, parse,alpha,digit,lower,upper,other,lexical,satisfy,optional,literal,untilP,untilParser,matchP) where ... (see attachment for files) Regards, Keean. parser.tgz Description: application/compressed-tar ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: Network parsing and parsec
John Goerzen wrote: On Tue, Sep 20, 2005 at 02:29:12PM +0100, Keean Schupke wrote: It's unclear to me exactly how to mix the IO monad with Parsec. It doesn't really seem to be doable. Not to mention that if hGetContents is used, the Handle has to be put into non-buffering mode, which means one syscall per character read. Terribly slow. Does it? I didn't think so ... strace seems to say yes. Thats odd, the source code seems to suggest that when you read past the end of the buffer it reads the next entire buffer (it has cases for each possible buffer configuration, line, block and none) - and I can think of no reason _why_ it cannot use buffering... I would think that it's a bug if it is the case. Regards, Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: Network parsing and parsec
Here's the code from hGetContents (base/GHC/IO.lhs): -- we never want to block during the read, so we call fillReadBuffer with -- is_line==True, which tells it to just read what there is. lazyReadBuffered h handle_ fd ref buf = do catch (do buf - fillReadBuffer fd True{-is_line-} (haIsStream handle_) buf lazyReadHaveBuffer h handle_ fd ref buf ) -- all I/O errors are discarded. Additionally, we close the handle. (\e - do handle_ - hClose_help handle_ return (handle_, ) ) So, it reads whatever is available, further description is available from the definition of fillReadBuffered: -- For a line buffer, we just get the first chunk of data to arrive, -- and don't wait for the whole buffer to be full (but we *do* wait -- until some data arrives). This isn't really line buffering, but it -- appears to be what GHC has done for a long time, and I suspect it -- is more useful than line buffering in most cases. So for a disc buffer I would expect 1 complete buffer to be returned most of the time, for a network read, I guess one packet (MTUs) worth should be expected... Regards, Keean. Keean Schupke wrote: John Goerzen wrote: On Tue, Sep 20, 2005 at 02:29:12PM +0100, Keean Schupke wrote: It's unclear to me exactly how to mix the IO monad with Parsec. It doesn't really seem to be doable. Not to mention that if hGetContents is used, the Handle has to be put into non-buffering mode, which means one syscall per character read. Terribly slow. Does it? I didn't think so ... strace seems to say yes. Thats odd, the source code seems to suggest that when you read past the end of the buffer it reads the next entire buffer (it has cases for each possible buffer configuration, line, block and none) - and I can think of no reason _why_ it cannot use buffering... I would think that it's a bug if it is the case. Regards, Keean. ___ 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
Re: [Haskell-cafe] Re: Network parsing and parsec
John Goerzen wrote: On Tue, Sep 20, 2005 at 03:05:25PM +0100, Keean Schupke wrote: strace seems to say yes. Thats odd, the source code seems to suggest that when you read past the end of the buffer it reads the next entire buffer (it has cases for each possible buffer configuration, line, block and none) - and I can think of no reason _why_ it cannot use buffering... I would think that it's a bug if it is the case. Because the next entire buffer might consume more data than the remote has sent. That results in deadlock. Would it not be usual to have a timeout incase of dropped connection? Regards, Keean. (Btw, did you look at the Parser Monad-Transformer?) ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell] Mixing monadic and non-monadic functions
Malcolm Wallace wrote: Wolfgang Jeltsch [EMAIL PROTECTED] writes: I'm not sure exactly what you have in mind. Obviously I want something that applies to all functions, with any number of arguments, and not just (+). Furthermore, it should handle cases like 1+[2,3] where only one value is monadic. I doubt that it is a good thing to extend the language in a way that such far reaching declarations are automatically generated. I agree. The original request was for something like [1,2] + [3,4] to be automatically lifted into a monad. But surely it is not too difficult to define the required behaviour precisely (and only) where needed, e.g. (+.) = liftM2 (+) [1,2] +. [3,4] Why not make the monad an instance of Num, then you do not proliferate meaningless similar symbols... besides which I am sure all the good ones are used in libraries already (like +. + etc) ;) instance (Monad m, Show a) = Show (m a) ... instance (Monad m, Ord a) = Ord (m a) ... instance (Monad m, Num a,Show (m a),Ord (m a)) - Num (m a) where (+) = liftM2 (+) The instances for Show and Ord can be empty if you don't need the functionality... Regards, Keean. ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Mixing monadic and non-monadic functions
Keean Schupke wrote: I'm not sure exactly what you have in mind. Obviously I want something that applies to all functions, with any number of arguments, and not just (+). Furthermore, it should handle cases like 1+[2,3] where only one value is monadic. Just noticed the 1+[1,2] case... I am not certain whether this is possible - it is outside the scope of the formal definiton of Haskell and may rely on implementation details of the compiler/interpreter. Effectivly we need to redefine list as a class, then (Num a) can be made an instance of the class... See my implementation of Joy in the HList library. (this lifts numbers into an AST rather than a list) - this however uses type level programming and has problems with non static types (IE you need to use existentials for lists who's values is not known at compile time)... The easy answer is to define a type that contains both singletons and lists... although the type constructors may not look as neat. Regards, Keean. ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Mixing monadic and non-monadic functions
Can't you do automatic lifting with a Runnable class: class Runnable x y where run :: x - y instance Runnable (m a) (m a) where run = id instance Runnable (s - m a) (s - m a) where run = id instance (Monad m,Monad n,MonadT t m,Runnable (m a) (n a)) = Runnable (t m a) (n a) where run = run . down instance (Monad m,MonadT t m,Monad (t m)) = Runnable (t m a) (m a) where run = down Where: class (Monad m,Monad (t m)) = MonadT t m where up :: m a - t m a down :: t m a - m a For example for StateT: downST :: Monad m = StateT st m a - (st - m a) downST m = \st - do (_,a) - runST m st return a downST' :: Monad m = (b - StateT st m a) - (st - b - m a) downST' m = \st b - do (_,a) - runST (m b) st return a instance (MonadState st (StateT st m),Monad m,Monad n,Runnable (st - m s) (st - n s)) = Runnable (StateT st m s) (st - n s) where run = run . downST instance (MonadState st (StateT st m),Monad m) = Runnable (StateT st m s) (st - m s) where run = downST Keean. Frederik Eaton wrote: Hi, Sean's comment (yeah, it was like a billion years ago, just catching up) is something that I've often thought myself. I want the type system to be able to do automatic lifting of monads, i.e., since [] is a monad, I should be able to write the following: [1,2]+[3,4] and have it interpreted as do {a-[1,2]; b-[3,4]; return (a+b)}. Also, I would have Reader (+1) + Reader (+4) == Reader (\x - 2*x+5) The point I want to make is that this is much more general than IO or monads! I think we all understand intuitively what mathematicians mean when they add two sets {1,2}+{3,4} (i.e. { x+y | x\in {1,2}, y\in {3,4}}) or when they add functions (f+g)(x) where f(x)=x+1 and g(x)=x+4 So automatic lifting is a feature which is very simple to describe, but which gives both of these notations their intuitive mathematical meaning - not to mention making monadic code much tidier (who wants to spend their time naming variables which are only used once?). I think it deserves more attention. I agree that in its simplest incarnation, there is some ugliness: the order in which the values in the arguments are extracted from their monads could be said to be arbitrary. Personally, I do not think that this in itself is a reason to reject the concept. Because of currying, the order of function arguments is already important in Haskell. If you think of the proposed operation not as lifting, but as inserting `ap`s: return f `ap` x1 `ap` ... `ap` xn then the ordering problem doesn't seem like such a big deal. I mean, what other order does one expect, than one in which the arguments are read in the same order that 'f' is applied to them? Although it is true that in most of the instances where this feature would be used, the order in which arguments are read from their monads will not matter; yet that does not change the fact that in cases where order *does* matter it's pretty damn easy to figure out what it will be. For instance, in print (a: ++ readLn ++ \nb: ++ readLn) two lines are read and then printed. Does anybody for a moment question what order the lines should be read in? Frederik On Tue, Mar 23, 2004 at 12:55:56PM -0500, Sean E. Russell wrote: On Tuesday 23 March 2004 11:36, Graham Klyne wrote: I think you're a rather stuck with the temporary variables (which they're not really), but it might be possible to hide some of the untidiness in an auxiliary monadic function. That seems to be the common suggestion: write my own visitors. I'm just surprised that there isn't a more elegant mechanism for getting interoperability between monadic and non-monadic functions. The current state of affairs just seems awkward. [Warning: quasi-rant] Caveat: I'm not smart enough, and I don't know enough, to criticize Haskell, so please don't misconstrue my comments. To quote Einstein: When I'm asking simple questions and I'm getting simple answers, I'm talking to God. I simply mistrust, and therefore question, systems where simple things are overly involved. The standard explaination about why monads are so troublesome always sounds like an excuse to me. We have monads, because they allow side-effects. Ok. If programs that used side effects were uncommon, I'd be fine with them being troublesome -- but they aren't. Maybe it is just me, but my Haskell programs invariably develop a need for side effects within a few tens of lines of code, whether IO, Maybe, or whatnot. And I can't help but think that language support to make dealing with monads easier -- that is, to integrate monads with the rest of the language, so as to alleviate the need for constant lifting -- would be a Good Thing. Hmmm. Could I say that Haskell requires heavy lifting? -- ### SER ###
Re: [Haskell-cafe] embedding prolog in haskell.
Thanks for that, altough I have completely rewritten it! Here's the new implementation: unify :: Subst - (Term,Term) - [Subst] unify sigma (s,t) = let s' = if isVar s then subst s sigma else s t' = if isVar t then subst t sigma else t in if isVar s' s'==t' then [sigma] else if isFunc s' isFunc t' then if fname s' == fname t' arity s' == arity t' then unify' sigma (terms s') (terms t') else [] else if not (isVar s) then unify sigma (t',s') else [s' ~ t' : sigma] unify' :: Subst - [Term] - [Term] - [Subst] unify' s (t0:ts) (u0:us) = case unify s (t0,u0) of s@(_:_) - unify' (concat s) ts us _ - [] unify' s [] [] = [s] unify' _ _ _ = [] Once again, thoughts or improvements greatly appreciated... Regards, Keean. Fergus Henderson wrote: You should delete the line above. It's not needed and could cause serious efficiency problems. With that line present, unifying two lists of length N which differ only in the last element would take time proportional to N squared, but without it, the time should be linear in N. unify s (Var x,t) = [(x,t):s] -- no occurs check unify s (t,Var x) = [(x,t):s] -- no occurs check These are not right; you need to look up the variable x in the substitution s, and if it is already bound, then you need to unify what it is bound to with the term t. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] pros and cons of static typing and side effects ?
Martin Vlk wrote: On pondělà 29 srpna 2005 8:57, Ketil Malde wrote: It contains descriptions of lots of real-world problems and how They are only implementing TRUTH and CWB, no? Yes, and lots of real-world situations that they faced during the development. That's what I meant. I would like to see more discussion of what is impoverished about the environments, and what they consider mainstream programming languages. Certainly the authors could have discussed this in the main part of the paper? Please read section 5 in the paper. I'm not sure the authors are even aware or the existence of interactive environments (e.g. Hugs and GHCi are not mentioned, only Haskell *compilers*). I am very sure they are aware of them. Interactive interpreters are simply not enough of a tool for commercial development - more sophisticated tools are necessary. In Haskell we don't even have basic things like code structure visualisation, efficient browsing and fully language-aware editor with typing support etc. This is one of the ways of distinguishing the mainstream languages. Mainstream means that enough people use them for someone to put in the effort to build the tools. I have used IDEs (Borlands delphi, MS VisualC++), and I prefer working with 'vi' and multiple shell windows. vi has such a quick startup time that you can swap between files easily, and it does syntax highlighting of many languages including Haskell. Some of the languages mentioned (Python) also have no real IDE, so that kind of undermines the point. I have written commerical code in many languages (including Haskell) and I work the same way for all of them. The closest anyone in my company comes to an IDE is python programming in Zope... As for debugging I have yet to find a situation that a debugger handles better than a couple of carefully places output statements. If you want to inspect the values of variables in a loop thats going wrong, just output them, and redirect the program output to a file... you can then run the program and inspect the resulting dataset to daignose the problem. Regards, Keean. ___ 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
Re: [Haskell-cafe] Re: Oracle + Haskell advice?
Well, I'll put my hand up, I use Haskell with databases and web stuff... Unfortunately when I started the common tools were not available. I have a home-grown Haskell-Servlet server, with monadic continuation based HTML composition and a HaskellDB like database layer. It all works very well, but being written for internal use (and me being lazy) it has only those features that I need. It is however designed as an integrated Web-Application platform... I was considering releasing it - but since I started other projects like HaskellDB restarted, WASH was written, HSQL started to support unix, and somebody added plugins to the Haskell Web-Server - So I didn't bother, although I am still using it myself... Still I now know that HaskellDB has significant limitations, and the relational algebra approach I took is far more robust and flexable... I don't have time to take this from a usable but incomplete project to a fully implemented API - what I mean here is that not all ODBC calls are implemented, some SQL features might be missing, some tags are not defined... not all HTTP requests and errors are generated, oh and there's no documentation. If anyone were interested in using/contributing I could give CVS access to the code. Keean. Brian Strand wrote: We run Suse 9.3 on x86 and x86-64; unixODBC does come out of the box here. If Takusen doesn't work out for some reason, I'll check into HSQL + unixODBC. Thanks for the advice, Brian ___ 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
Re: [Haskell-cafe] embedding prolog in haskell.
Okay, I have found the missing definition (code was split by page break), and found the type error: type Subst = [(Var,Term)] should be: type Subst = [(Vname,Term)] And have written a simple implementation of unify from a description of the algorithm. I was wondering if anyone has any comments on my implementation of unify? For example can the algorithm be simplified from my nieve attempt? Most importantly is it correct? type Subst = [(Vname,Term)] data Term = Func Fname [Term] | Var Vname deriving (Eq,Show) type Fname = String data Vname = Name String | Auto Integer deriving (Eq,Show) unify :: Subst - (Term,Term) - [Subst] unify s (t,u) | t == u = [s] unify s (Var x,t) = [(x,t):s] -- no occurs check unify s (t,Var x) = [(x,t):s] -- no occurs check unify s (Func f ts,Func g us) | f == g = unify' s ts us | otherwise = [] unify' :: Subst - [Term] - [Term] - [Subst] unify' s [] [] = [s] unify' s (t0:ts) (u0:us) = case unify s (t0,u0) of s@(_:_) - unify' (concat s) ts us _ - [] Keean. Keean Schupke wrote: Does anyone know if the source code for the embedded prolog (by Silvija Seres Michael Spivey) is available for download from anywhere? I have read the paper and found some of the types are wrong, some critical definitions are missing, and the definition of unify is missing. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] embedding prolog in haskell.
Christian Maeder wrote: Keean Schupke wrote: implementation of unify? For example can the algorithm be simplified from my nieve attempt? Most importantly is it correct? It will not be correct without occurs check. You may also get different terms for the same variable in your substitution list. Prolog does not use an occurs check... and this is embedding prolog. However I accept this point, thats why there was the comment about no occurs check in the code. I actually want to cope with recursive definitions as Prolog does, so the solution to: X = f(X) should be: f(f(f(f(... which is an infinite recursion. The simplest form of unification does not take a substitution as input and uses functions to compose two substitutions and to apply a substitution to a term. unify :: Subst - (Term,Term) - [Subst] This signature came from the paper... The input subst is an accumulator and it would normally be Id when calling - so there is effectively no input substitution. Do you ever get real lists? The result type Maybe Subst is more appropriate. No, I dont think the algorithm gives real lists, Maybe would be better, although I think I will get it working before playing with changing the rest of the code. Is it possible to ever have more than one meaningful answer from unification? unify' s [] [] = [s] unify' s (t0:ts) (u0:us) = case unify s (t0,u0) of s@(_:_) - unify' (concat s) ts us _ - [] input lists of different lengths should not cause a runtime error but only a unification failure (indicated by Nothing or [] in your case.) Aha, a genuine bug... thanks! HTH Christian Here's a part of my version: unify' (t0:ts) (u0:us) = do s1 - unify (t0,u0) s2 - unify' (map (applySubst s1) ts) (map (applySubst s1) us) return (composeSubst s1 s2) I am now using: unify' :: Subst - [Term] - [Term] - [Subst] unify' s (t0:ts) (u0:us) = case unify s (t0,u0) of s@(_:_) - unify' (concat s) ts us _ - [] unify' s [] [] = [s] unify' _ _ _ = [] Regards, Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] static typing and interactivity
I look at the source code and think about it... Generally I code in vi, then run ghci, or compile and run. I find from experience the type errors are normally easy to fix, you just look at the error, and study the structure of the function. If I still have problems I edit the code to return or output intermediate values. From years of doing this I can generally spot all my mistakes quickly... leaving only those situations where I don't fully understand the algorithm as requiring serious thought. Of course these are precisely those kind of problems for which a debugger is not much good either. Keean. Jake Luck wrote: One slight annoyance using Haskell is the inability to load modules with type problems in the interactive environment (i.e. GHCi). When I have a type error, it would be nice to have an interactive way to explore what the compiler thinks about the types involved -- as it is, I have to resort to adding type signatures more or less at random to narrow down the problem. I'm not sure if it is technically feasible to (partially) load a module with definitions that fail type checking, but if it were, I thing it would make developing Haskell programs even nicer :-) Along similiar lines, it would be quite nice if one can mark their haskell code(working or not) with breakpoints and drop the programmer into GHCi so they can poke around, especially inside a do-construct. e.g. something the evalutation engine can check during reduction maybe? I find myself writing a lot of testing frameworks, maybe this is a good thing!, when I program. How do most of the folks here debug their large code base? jake ___ 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] embedding prolog in haskell.
Does anyone know if the source code for the embedded prolog (by Silvija Seres Michael Spivey) is available for download from anywhere? I have read the paper and found some of the types are wrong, some critical definitions are missing, and the definition of unify is missing. Regards, Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: Functional Dependencies
Picked up on this late... I have working examples of add etc under ghc/ghci... I can't remeber all the issues involved in getting it working, but I can post the code for add if its any use? Keean. Dirk Reckmann wrote: Am Donnerstag, 11. August 2005 11:41 schrieb Simon Peyton-Jones: You raise a vexed question, which has been discussed a lot. Should this typecheck? class C a b | a - b instance C Int Bool f :: forall a. C Int a = a - a f x = x GHC rejects the type signature for f, because we can see that 'a' *must be* Bool, so it's a bit misleading to universally quantify it. Ok, maybe this is a reasonable choice. But why does the attached program work? ghci presents a unique type for the universal quantified function 'eight': *Add :t eight eight :: Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))) Best regards, Dirk Simon | -Original Message- | From: [EMAIL PROTECTED] [mailto:glasgow-haskell-users- | [EMAIL PROTECTED] On Behalf Of Dirk Reckmann | Sent: 21 July 2005 10:30 | To: glasgow-haskell-users@haskell.org | Subject: Functional Dependencies | | Hello everybody! | | I wanted to have some fun with functional dependencies (see | http://www.cs.chalmers.se/~hallgren/Papers/wm01.html), and tried some | examples from this paper as well as some own experiments. The idea is to use | the type checker for computations by abuse of type classes with functional | dependencies. | | The example in the attached file is taken from the above paper. Due to the | functional dependencies, I expected the type of seven to be uniquely | determined to be (Succ (Succ (Succ ...))), i. e. seven, but ghc (version 6.4) | gives me following error message: | | Add.hs:14:0: | Couldn't match the rigid variable `a' against `Succ s' | `a' is bound by the type signature for `seven' | Expected type: Succ s | Inferred type: a | When using functional dependencies to combine | Add (Succ n) m (Succ s), arising from the instance declaration at | Add.hs:11:0 | Add (Succ (Succ (Succ Zero))) (Succ (Succ (Succ (Succ Zero a, | arising from the type signature for `seven' at Add.hs:13:0-77 | When generalising the type(s) for `seven' | | However, using the definition of Add to define Fibonacci numbers does work, | and a similar function declaration can be used to compute numbers by the type | checker. | | The same definition of Add works in Hugs... | | So, is this a bug in ghc, or am I doing something wrong? | | Thanks in advance, | Dirk Reckmann {-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-} module Add where data Zero data Succ n class Add n m s | n m - s instance Add Zero m m instance Add n m s = Add (Succ n) m (Succ s) class Fib n f | n - f instance Fib Zero (Succ Zero) instance Fib (Succ Zero) (Succ Zero) instance (Fib n fib_n, Fib (Succ n) fib_s_n, Add fib_n fib_s_n sum ) = Fib (Succ (Succ n)) sum eight :: Fib (Succ (Succ (Succ (Succ (Succ Zero) n = n eight = undefined ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: [Haskell-cafe] Re: [Haskell] pros and cons of static typing and side effects ?
My 2-pence worth on static typing. Static typing to me seems to be a simplified form of design by contract. There are some things about a program that can be proved true for all time. Types are an example of such a thing. We can use type systems to make assertions about properties that must be true for all time, and then reject programs that break these rules. One of the easyest things to prove about a program is that all values and references are handled correctly - hence you will never see a segmentation fault due to bad programming, it is just impossible (of course the run-time-system which is written in C may cause one, but that cannot be due to a bug in your program). Taking one of your points in more detail:The single type property for lists is not a problem due to the presence of algebraic datatypes, for example want a list of strings and ints: data StringOrInt = IsString String | IsInt Int type ListOfStringOrInt = [StringOrInt] You can also have lists of records... Think about it for a bit and you will see there are very few cases where you need to have a list of 'general types'... You can even use existential types to create lists of things with a common interface, where you do not know in advance what types you may need: data XWrap = XWrap (forall a . Show a = a) type ListXWrap = [XWrap] This creates a list where the items can be any type, provided they are a member of the class Show. Also the only functions you can call on the items in the list are the methods of the Show class... Of course you can have multiple type constraints (forall a . (Show a,Num a) = a). This is not the limit of how far we can go with static typing. We can choose any provable property about a program... for example we could ask that the compiler prove that the heap size of the program never exceeds 10M (not possible in any current language - but is an extension of the concept). Other things we can do ... with dependant types we can ask the compiler to prove the correctness of sorting algorithms. If we define an ordered list tgo be one where each element must be larger than the preceding one: data OrderedIntList = Cons (a::Int) (l::OrderedList) | Nil {- where a = head l -} data IntList = [Int] We can now define our sorting function: quicksort :: IntList - OrderedIntList By this we are asking the compiler to prove (by induction) that the function provided can only result in correctly ordered lists - irrespective of what arguments it is given (ie proved true for any input)... This would have to be done symbolically but is not beyond what can be achieved using logic programming. To implement this, a Prolog program containing all the type constraints of the function definition and the proposed type would be evaluated... Prolog will say yes or no to the function. Regards, Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] pros and cons of static typing and side effects ?
Benjamin Franksen wrote: On Tuesday 16 August 2005 21:56, Keean Schupke wrote: You can even use existential types to create lists of things with a common interface, where you do not know in advance what types you may need: data XWrap = XWrap (forall a . Show a = a) type ListXWrap = [XWrap] You probably meant to write data XWrap = forall a . Show a = XWrap a or, in GADT style (which I find a bit more intuitive here): data XWrap where XWrap :: Show a = a - XWrap Yes I always get confused by the notation Haskell uses... I used explicit universal quantification by mistake. I tried to think logically about the encapsulation existential types represent - and got the wrong form. I for one would like to see the use of 'exists' as a keyword for existential types, after all different symbols are used in modal logic (upside-down-A for forall, and backwards-E for exists). Regards, Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] pros and cons of static typing and side effects ?
Lennart Augustsson wrote: Keean Schupke wrote: quicksort :: IntList - OrderedIntList By this we are asking the compiler to prove (by induction) that the function provided can only result in correctly ordered lists - irrespective of what arguments it is given (ie proved true for any input)... This would have to be done symbolically but is not beyond what can be achieved using logic programming. But the output being ordered is not enough. The output should also be a permutation of the input. This can, of course, be expressed in a similar way. Yes, the easiest way would be to constrain the output list to be a subset of the input list, and vice-versa... something like: quicksort :: (x::IntList) - (y::OrderedIntList) {- where x : y x : y -} of course you would have to use the correct definition of subset - you really want to treat the list as a multi-set. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: [Haskell] pros and cons of static typing and side effects ?
Benjamin Franksen wrote: as in data XWrap = Show a = XWrap a I always thought this was a pretty nice idea. Wow, I hadn't thought of that... of course you still need to explicitly give the universal quantification if you need it. I guess the best option is to make it optional, as I still like the look of: data XWrap = exists a . Show a = XWrap a It kind of say this is existential quantification in large freindly letters... (A bit like a book I once read - except that said Don't Panic) Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] matrix computations based on the GSL
Henning Thielemann wrote: My objections to making everything a matrix were the objections I sketched for MatLab. The example, again: If you write some common expression like transpose x * a * x Which just goes to show why haskell limits the '*' operator to multiplying the same types. Keep this to Matrix-times-Matrix operators. Surely a vector is a 1xN matrix? And in terms of matrices a 1x1 matrix and a scalar are the same? I don't see the point of having separate matix and vector types... just have 'matrix constructors: matrix :: [[a]] - Matrix a vector :: [a] - Matrix a scalar :: a - Matrix a I don't see any problems with this, and it lets you define the matrix exponential: instance Floating a = Floating (Matrix a) where exp = undefined Type of exp in Floating is (a - a - a), so substituting the class parameter gives: exp :: Matrix a - Matrix a - Matrix a, however you can only compute the matrix exponential (x^y) for scalar-x matrix-y or matrix-x scalar-y... I feel using separate types for vectors and scalars just overcomplicates things... then both the human reader and the compiler don't know whether x is a true matrix or if it simulates a column or a row vector. It may be that 'x' is a row vector and 'a' a 1x1 matrix, then the expression denotes a square matrix of the size of the vector simulated by 'x'. It may be that 'x' is a column vector and 'a' a square matrix. Certainly in most cases I want the latter one and I want to have a scalar as a result. But if everything is a matrix then I have to check at run-time if the result is a 1x1 matrix and then I have to extract the only element from this matrix. If I omit the 1x1 test mistakes can remain undiscovered. I blame the common notation x^T * A * x for this trouble since the alternative notation x, A*x can be immediately transcribed into computer language code while retaining strong distinction between a vector and a matrix type. If x is a matrix and y is a matrix then x * y can only be interpreted in one simple way - no special cases. Sometimes you may need to transpose a 1xN into an Nx1 but at least you will get an 'error' if you try to use the wrong type... More examples? More theory? More complexity? Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] matrix computations based on the GSL
Henning Thielemann wrote: Let me elaborate on that: In some cases putting vectors as columns into a matrix then applying a matrix operation on this matrix leads to the same like to 'map' a matrix-vector operation to a list of vectors. But in other cases (as the one above) this is not what you want. I consider it as an incidence not as a general principle if this kind of extension works. Let's consider another example: The basic definition of the Fourier transform is for vectors. MatLab wants to make the effect of vector operations consistent for row and column vectors, thus Okay, this approach is starting to make sense to me... I can see now that Vectors are a different type of object to Matrices. Vectors represent points in N-Space and matrices represent operations on those points (say rotations or translations)... But it seems we can represent translations as adding vectors or matrix operations (although we need to introduce the 'extra' dimension W... and have an extra field in vectors that contains the value '1'). (3D translation) [x,y,z,1] * [[0,0,0,0],[0,0,0,0],[0,0,0,0],[dx,dy,dz,dw]] = [x+dx,y+dy,z+dz,1+dw] but how is this different from adding vectors? If we allow vector addition then we no longer have the nice separation between values and linear operators, as a value can also be a linear operator (a translation)? Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] matrix computations based on the GSL
Henning Thielemann wrote: I'm excited if your code gets swamped by conversions between Double and Matrix then. I really plead for representing everything with strings, this is the most simple and most flexible solution! :-] Surely its a case of balancing the advantage of type safety against the added complexity. The point after all is to reduce bugs. Type-sigs reduce one type of bug, at the cost of an increase in complexity. My argument is that at some point the probability of introducing errors due to the increased complexity outweighs the reduction in the probability of error due to type-safety? I think this is a pragmatic point, that cannot be argued with, all you can argue over is where in the continuum this point is. As such we were dicussing the complexity/type-safety trade off with respect to matrices - to go from this to such a sweeping statment... is like saying 'if I can't have it my way I don't want anything at all... Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] matrix computations based on the GSL
Henning Thielemann wrote: Do you mean [x,y,z,1] * [[1,0,0,0],[0,1,0,0],[0,0,1,0],[dx,dy,dz,dw+1]] ? Erm, yes thats what I meant ... but you obviously got the point. but how is this different from adding vectors? If we allow vector addition then we no longer have the nice separation between values and linear operators, as a value can also be a linear operator (a translation)? ??? Well if a vector can be a linear-operator, then surely it _is_ a matrix! Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Re: matrix computations based on the GSL
Is a matrix is a linear operation on a vector, does it not make sense to define matrix applicaion: mapply :: Matrix - Vector - Vector Then you can define say: rotate90 = mapply rotationMatrix90 v' = rotate90 v Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] matrix computations based on the GSL
Henning Thielemann wrote: In general a vector need not to be a linear operator. You talked about vector translation, translation is not a linear operator. You gave some process to map the problem to somewhere, where it becomes a linear operator. Other people said that the scalar product with a fixed vector is a linear operator. That's true. Now what is a natural interpretation of a vector as linear operator? The scalar product or the translation? Vectors can be used and abused for many things but an object which can be called a vector (because of its ability of to be added and to be scaled) is not a linear operator itself and does not naturally represent one. So the linear operator is translation (ie: + v)... effectively 'plus' could be viewed as a function which takes a vector and returns a matrix (operator) (+) :: Vector - Matrix Which could also be called 'translate'. So 'translate' takes a vector and returns a linear-operator which can be applied to a vector: mapply (translate vector1) vector2 So I guess I could now ask, why allow vector addition at all? Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] matrix computations based on the GSL
Henning Thielemann wrote: On Fri, 8 Jul 2005, Keean Schupke wrote: So the linear operator is translation (ie: + v)... effectively 'plus' could be viewed as a function which takes a vector and returns a matrix (operator) (+) :: Vector - Matrix Since a matrix _is_ not a linear map but only its representation, this would not make sense. As I said (v+) is not a linear map thus there is no matrix which represents it. A linear map f must fulfill f 0 == 0 But since v+0 == v the function (v+) is only a linear map if 'v' is zero. I can't see how to fit in your vector extension by the 1-component. Eh? Translation is a linear operation no? Adding vectors translates the first by the second (or the second by the first - the two are isomorphic)... A translation can be represented by the matrix: 1 0 0 0 0 1 0 0 0 0 1 0 dx dy dz 1 So the result of v+ is this matrix. In other words this matrix is the 'vector addition operator'... providing you pad the vectors with an additional '1' at the end. So if: translate :: Vector - Matrix [x,y,z,1] = [[1,0,0,0],[0,1,0,0],[0,0,1,0],[x,y,z,1]] we can create a matrix representing translation from: translate [3,4,5,1] and can apply this translation to another vector: mapply (translate [3,4,5,1]) [2,3,4,1] = [5,7,9,1] All I was saying is that following this, partial application of vector addition: [3,4,5] + [2,3,4] = [5,7,9] but partially applying: ([3,4,5] +) would be a the matrix defined above as (translate [3,4,5,1]) ... Of course this has the drawback that you need an extra dimension in you vectors and matrices to cope with translation. Anyway I have more or less convinced myself that separating vectors and matrices is the right thing to do... I was just trying to define vector addition in terms of a matrix operation for neatness. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Re: matrix computations based on the GSL
Henning Thielemann wrote: does it not make sense to define matrix applicaion: mapply :: Matrix - Vector - Vector Then you can define say: rotate90 = mapply rotationMatrix90 v' = rotate90 v ... that's what I said about mulVec. I guess that means we agree... Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] matrix computations based on the GSL
Henning Thielemann wrote: I'm uncertain about how who want to put the different kinds of multiplication into one method, even with multi-parameter type classes. You need instances (*) :: Matrix - Matrix - Matrix (*) :: RowVector - Matrix - RowVector (*) :: Matrix - ColumnVector - ColumnVector (*) :: RowVector - ColumnVector - Scalar (*) :: ColumnVector - RowVector - Matrix (*) :: Scalar - RowVector - RowVector (*) :: RowVector - Scalar - RowVector (*) :: Scalar - ColumnVector - ColumnVector (*) :: ColumnVector - Scalar - ColumnVector but you have to make sure that it is not possible to write an expression which needs (*) :: Matrix - RowVector - RowVector Further you need transpose :: RowVector - ColumnVector transpose :: ColumnVector - RowVector transpose :: Matrix - Matrix and you must forbid, say transpose :: RowVector - RowVector Of course if they are all of type Matrix this problem disappears. What is the difference between a 1xN matrix and a vector? Please explain... Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] matrix computations based on the GSL
David Roundy wrote: In short, especially since the folks doing the work (not me) seem to want plain old octave-style matrix operations, it makes sense to actually do that. *Then* someone can implement an ultra-uber-tensor library on top of that, if they like. And I would be interested in a nice tensor library... it's just that matrices need to be the starting point, since they're where most of the interesting algorithms are (that is, the ones that are interesting to me, such as diagonalization, svd, matrix multiplication, etc). This is a really good idea. I would like a Matrix library soon, not in 6 years time. Slice it up into managable pieces and keep it simple! Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re[4]: [Haskell] Dynamic binding
Interestingly this is exactly the approach taken in the OOHaskell paper! The difference is we used extensible records with subtyping (from the HList paper) to implement inheritance and overloading, which you cannot do with ordinary Haskell records. So you statment that it is better to do it in Haskell, well we are both doing it in Haskell, and your proposed method is just a simplified version of what we are doing in the paper. Keean. Bulat Ziganshin wrote: Hello Ralf, Thursday, June 23, 2005, 11:36:20 AM, you wrote: just create list of draw functions itself: [drawCircle (10,10) 5, drawSquare (20,20) 10] RL No! the exercise is about lists of shapes RL not lists of results of drawing shapes. RL This is clearly a major difference. in cases where you need to call only one function on created objects, you can just insert in list calls to this functions (not their results! i suppose that drawXXX functions has ... - IO () type) in cases where you need to call several functions for this object, you can insert in list tuple or structure for each object, as i do in next example. original exercise was about OO way to solve some problem. i want to say that in Haskell it's better in most cases to use another, functional way RL Bulat wrote: for more complex tasks - declare interface as a structure: data ShapeInterface = Shape { draw :: IO (), moveTo :: Point - IO (), calcArea :: Float } RL No! You miss the point that the different shapes RL differ regarding state types. RL You don't have a chance when you use one datatype. this state is just don't need to appear in interface definition :) see for example: data ShapeInterface = Shape { draw :: IO (), calcArea :: Float } circle x y r = Shape { draw = drawCircle x y r, calcArea = pi*r*r } square x y size = Shape { draw = drawSquare x y size, calcArea = size*szie } figures = [circle 1 2 3, square 4 5 6, circle 7 8 9] if you need to maintain mutable state, this is also not a problem: data ShapeInterface = Shape { draw :: IO (), moveTo :: (Int,Int) - IO (), calcArea :: Float } circle x y r = do center - ref (x,y) return Shape { draw = val center = drawCircle r , moveTo = (center=:) , calcArea = pi*r*r } main = do figures - sequence [circle 1 2 3, square 4 5 6, circle 7 8 9] mapM_ draw figures mapM_ (moveTo (0,0)) figures mapM_ draw figures ref=newIORef val=readIORef (=:)=writeIORef RL haskell-cafe? as you wish :) ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
using the Intel compiler (icc)
Is it possible to get GCC to use the intel C compiler (ICC) instead of gcc? Keean. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: using the Intel compiler (icc)
Sorry, yes I mean getting GHC to use ICC instead of GCC... is it just a matter of a command line switch to give GHC the path to the compiler? Keean. Seth Kurtzberg wrote: Keean Schupke wrote: Is it possible to get GCC to use the intel C compiler (ICC) instead of gcc? Do you mean is it possible to get /GHC/ to use /ICC/? Otherwise I don't understand the question. Keean. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: [Haskell-cafe] Open mutable records
Have you seen the OOHaskell paper (the follow up to the HList paper)... It looks like you do much the same thing - with some differences... Would be interesting to get your comments on the paper: http://homepages.cwi.nl/~ralf/OOHaskell/ Keean. Einar Karttunen wrote: Hello I recently ended up hacking a quite concise implementation of mutable open (extensible) records in Haskell. Most of the ideas came from the HList-paper, but this seems like a very simple way of doing things. Run with ghci -fglasgow-exts -fallow-overlapping-instances. Import some stuff we are going to need later: import Control.Monad.Reader import Data.IORef import System Monad for mutable record calculations - to get implisit this/self in the OO sense. newtype OO t r = OO (ReaderT t IO r) deriving(Monad, MonadReader t, MonadIO) with :: s - OO s a - OO b a with this (OO c) = liftIO (runReaderT c this) ooToIO :: OO s a - IO a ooToIO (OO c) = runReaderT c undefined Records First the record constructor - followed by the terminator. data a :.: r = RC !a !r infixr :.: data END = END Next we define a field access method. class Select r f t | r f - t where (!) :: r - f - Ref t instance Select (Field f t :.: r) f t where (!) (RC (F x) _) _ = x instance Select r f t = Select (a :.: r) f t where (!) (RC _ t) = (!) t And finally the type of mutable fields. type Ref a = IORef a newtype Field name rtype = F (Ref rtype) Next we define a way to construct record values. infixr ## (##) :: v - OO s r - OO s ((Field f v) :.: r) (##) v r = do { h - liftIO (newIORef v); t - r; return (RC (F h) t) } end = return END :: OO s END Get the value of a field. value :: Select s f t = f - OO s t value a = do x - asks (\s - s!a) liftIO (readIORef x) Or set the value of a field. (-:) :: Select s f t = f - t - OO s () a -: b = do x - asks (\s - s!a) liftIO (writeIORef x b) And as a convenience add value to an int field. (+=) :: Select s f Int = f - Int - OO s Int a += b = do x - asks (\s - s!a) val - liftIO (readIORef x) let z = val+b z `seq` liftIO (writeIORef x z) return z Now implement the classic ocaml OO tutorial: data X = X type Point = Field X Int :.: END newPoint :: OO s Point newPoint = 0 ## end getX :: Select s X t = OO s t getX = value X move d = X += d data Color = Color type ColoredPoint = Field Color String :.: Point newColoredPoint :: String - OO s ColoredPoint newColoredPoint c = c ## 0 ## end color :: Select s Color t = OO s t color = value Color The code looks in more complex examples like this: ((~=) is prepending into list fields.) newArrival :: Patient - OO Hospital () newArrival patient = do with patient (HospitalVisits += 1) staff - value FreeStaff if staff 0 then do FreeStaff += (-1) Examination ~= patient with patient (do HospitalTime += 3 RemainingTime -: 3) else do Triage ~= patient main = ooToIO (do c1 - newPoint c2 - newColoredPoint green with c1 $ move 7 with c2 $ move 4 let p x = liftIO (print x) p = with c1 getX p = with c2 getX) - Einar Karttunen ___ 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
Re: [Haskell] Eternal Compatibility In Theory
robert dockins wrote: Is there a way to reliably and automatically check if two versions of a haskell module are interface compatible? No, because it would have to check whether the semantics of functions is the same, even if they are written differently. Of course, we cannot expect the computer to examine the semantics. We must rely on people to know when semantics change. Suppose I want to ask the easier question do these two text files implement haskell modules which are _type_ compatable?, how would I do it? Ie, I want the test to fail if I change the type of some function foo, or if I add a method to a class declaration etc. ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell Is this true? Can't you use an IDL to specify the interface more exactly. I would have thought a definition of the protocol was enough. If you define a protocol definition language then it should be possible to check both ends of the connection to see if the conform to the protocol. Keean. ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell-cafe] RFE: Extensible algebraic user-defined data types?
David Menendez wrote: The downside is that a function that might normally be typed Either A B - C now will have the type: (HTypeIndexed l, HTypeProxied l, HOccurs (Proxy (Left A)) l, HOccurs (Proxy (Right B)) l) = TIC l - C But it will accept a TIC (HEither A B) and a TIC (HNEither A B) and any other TIC that contains Left A and Right B among its possible values. [1] http://homepages.cwi.nl/~ralf/HList/ Of course the compiler will infer this type for you. I find it very handy to use explicitly typed funtions to compose constraints, thus avoiding the need to have big type signatures... something like: constrainInt :: Int - Int constrainInt = id constrainSomeClass :: SomeClass a = a - a constrainSomeClass = id you can then write: f i c = someFn (constrainInt i) (constrainSomeClass c) Where someFn has a complicated type like that above... In this way you can avoid having to specify all the constraints a function, and it effectively gives you the same functionality as partial type signatures. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Instances of constrained datatypes
Can you not define functor like Hughes defines a restricted monad (section 3 in the paper)... Keean Arjun Guha wrote: One way to do roughly what you want is to pass the dictionary yourself: data EqDict a = EqDict { leq :: a - a - Bool } data EqList a = EqList (EqDict a) [a] test :: EqList a - EqList a - Bool test (EqList dict (a0:as)) (EqList _ (b0:bs)) = (leq dict) a0 b0 This is like the `object-oriented approach' in John Hughes' paper. Let's switch to the set example in his paper: data EqDict a = EqDict { isEq:: a - a - Bool } data Set a = Set (EqDict a) [a] So, to make it a functor, as I originally wanted: instance Functor Set where fmap f (Set dict ls) = Set dict' ls' where ls' = nubBy (isEq dict') ls dict' = ??? There really isn't a way to define dict' for the resultant Set. -Arjun ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] List containing different types but all implementing the same class
You can do this like: data TTrue = TTrue data TFalse = TFalse data Nil = Nil data Cons a l = Cons a l class Constrain c a b | c a - b where constrain :: c - a - b data ZConstraint = ZConstraint instance Z a b = Constrain ZConstraint a b class List c l instance List c Nil instance (Constrain c a TTrue,List c l) = List c (Cons a l) Now define a class 'Z' using a fundep such that 'b' becomes TTrue if 'a' is in Z. class Z a b | a - b where instance (TypeEq a Int b,TypeEq a Float b,TOr a b c) = Z a c -- Int and Float are members of Z, TypeEq and TOr come from the -- HList library. Finally you can constrain the list: f :: List ZConstraint l - List ZConstraint l f x = x Regards, Keean. Bo Herlin wrote: Hi everyone. Being new to Haskell I wonder how I can make a list contain different types but all implementing the same class, like this: data X = X data Y = Y class Z a where f :: a - Int instance Z X where f x = 0 instance Z Y where f y = 1 test1 :: Z a = [a] test1 = [X,Y] test2 = map f test1 Is it possible to make this work? /Bo Herlin ___ 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
Re: [Haskell-cafe] Instances of constrained datatypes
I think it is more a problem of imlpementation than one of what is desirable. A Constrained data type: data (Eq v) = EqList v = EqList [v] The problem is how to get the dictionary for the class Eq to the application site: f :: EqList v - EqList v f (EqList (u0:us)) (EqList (v0:vs)) | v0 == u0 = ... Which of course does not work... the constraint needs to be in the function type signature: f :: Eq v = EqList v - EqList v Things are worse though, as even functions that use no methods of Eq will require the constraint. The constraint on the data type does not stop you construction EqLists from non Eq members... of course this gets detected the moment you try and use it in a constrained function. In other words using the constraint in the data type does nothing... you may as well just do: f :: Eq v = [v] - [v] Infact I believe it was decided to remove the feature from Haskell98 entirely, but there was apparently some use for the 'syntax' although with a different effect. Keean. Cale Gibbard wrote: I don't believe you can, but it would be nice. There are certain types, such as Set, where it's not really possible to just remove the constraint from the data declaration, and yet it would be nice if sets could be instances of Monad and Functor. Currently, to be an instance of Functor or Monad, your type has to be a functor defined on the whole category of types. Could this issue be fixed somehow? Constrained instances would make various typeclass-based libraries more applicable. What would it break to allow instances where the types of functions defined by the typeclass are further restricted? I suppose that checking that types are correct becomes more difficult and non-local, because functions which are defined using the typeclass won't already have that constraint for obvious reasons. Still, the constraint is in the instance, which must be around when the functions actually get applied. There are probably bad interactions with the module system, but I'm not certain. People must have talked about this before... was a consensus reached that I'm not aware of? - Cale On Apr 6, 2005 2:10 AM, Arjun Guha [EMAIL PROTECTED] wrote: This is a contrived example, but contains the essence of what I'd like to do. Suppose I have this datatype: data (Eq v) = EqList v = EqList [v] I'd like to make it an instance of Functor. However, fmap takes an arbitrary function of type a - b. I need an Eq constraint on a and b. Is there any way to do this without creating my own `EqFunctor' class with explicitly-kinded quantification: class (Eq a) = EqFunctor (f :: * - *) a where eqfmap:: (Eq b) = (a - b) - f a - f b Thanks. -Arjun ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Instances of constrained datatypes
One way to do roughly what you want is to pass the dictionary yourself: data EqDict a = EqDict { leq :: a - a - Bool } data EqList a = EqList (EqDict a) [a] test :: EqList a - EqList a - Bool test (EqList dict (a0:as)) (EqList _ (b0:bs)) = (leq dict) a0 b0 In this way the definition of equality on elements of type 'a' is passed with the list type, so it can be used wherever the list type is used, without requiring extra constraints. Keean. Keean Schupke wrote: I think it is more a problem of imlpementation than one of what is desirable. A Constrained data type: data (Eq v) = EqList v = EqList [v] The problem is how to get the dictionary for the class Eq to the application site: f :: EqList v - EqList v f (EqList (u0:us)) (EqList (v0:vs)) | v0 == u0 = ... Which of course does not work... the constraint needs to be in the function type signature: f :: Eq v = EqList v - EqList v Things are worse though, as even functions that use no methods of Eq will require the constraint. The constraint on the data type does not stop you construction EqLists from non Eq members... of course this gets detected the moment you try and use it in a constrained function. In other words using the constraint in the data type does nothing... you may as well just do: f :: Eq v = [v] - [v] Infact I believe it was decided to remove the feature from Haskell98 entirely, but there was apparently some use for the 'syntax' although with a different effect. Keean. Cale Gibbard wrote: I don't believe you can, but it would be nice. There are certain types, such as Set, where it's not really possible to just remove the constraint from the data declaration, and yet it would be nice if sets could be instances of Monad and Functor. Currently, to be an instance of Functor or Monad, your type has to be a functor defined on the whole category of types. Could this issue be fixed somehow? Constrained instances would make various typeclass-based libraries more applicable. What would it break to allow instances where the types of functions defined by the typeclass are further restricted? I suppose that checking that types are correct becomes more difficult and non-local, because functions which are defined using the typeclass won't already have that constraint for obvious reasons. Still, the constraint is in the instance, which must be around when the functions actually get applied. There are probably bad interactions with the module system, but I'm not certain. People must have talked about this before... was a consensus reached that I'm not aware of? - Cale On Apr 6, 2005 2:10 AM, Arjun Guha [EMAIL PROTECTED] wrote: This is a contrived example, but contains the essence of what I'd like to do. Suppose I have this datatype: data (Eq v) = EqList v = EqList [v] I'd like to make it an instance of Functor. However, fmap takes an arbitrary function of type a - b. I need an Eq constraint on a and b. Is there any way to do this without creating my own `EqFunctor' class with explicitly-kinded quantification: class (Eq a) = EqFunctor (f :: * - *) a where eqfmap:: (Eq b) = (a - b) - f a - f b Thanks. -Arjun ___ 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
Re: [Haskell-cafe] Instances of constrained datatypes
One way to do roughly what you want is to pass the dictionary yourself: data EqDict a = EqDict { leq :: a - a - Bool } data EqList a = EqList (EqDict a) [a] test :: EqList a - EqList a - Bool test (EqList dict (a0:as)) (EqList _ (b0:bs)) = (leq dict) a0 b0 In this way the definition of equality on elements of type 'a' is passed with the list type, so it can be used wherever the list type is used, without requiring extra constraints. Keean. Keean Schupke wrote: I think it is more a problem of imlpementation than one of what is desirable. A Constrained data type: data (Eq v) = EqList v = EqList [v] The problem is how to get the dictionary for the class Eq to the application site: f :: EqList v - EqList v f (EqList (u0:us)) (EqList (v0:vs)) | v0 == u0 = ... Which of course does not work... the constraint needs to be in the function type signature: f :: Eq v = EqList v - EqList v Things are worse though, as even functions that use no methods of Eq will require the constraint. The constraint on the data type does not stop you construction EqLists from non Eq members... of course this gets detected the moment you try and use it in a constrained function. In other words using the constraint in the data type does nothing... you may as well just do: f :: Eq v = [v] - [v] Infact I believe it was decided to remove the feature from Haskell98 entirely, but there was apparently some use for the 'syntax' although with a different effect. Keean. Cale Gibbard wrote: I don't believe you can, but it would be nice. There are certain types, such as Set, where it's not really possible to just remove the constraint from the data declaration, and yet it would be nice if sets could be instances of Monad and Functor. Currently, to be an instance of Functor or Monad, your type has to be a functor defined on the whole category of types. Could this issue be fixed somehow? Constrained instances would make various typeclass-based libraries more applicable. What would it break to allow instances where the types of functions defined by the typeclass are further restricted? I suppose that checking that types are correct becomes more difficult and non-local, because functions which are defined using the typeclass won't already have that constraint for obvious reasons. Still, the constraint is in the instance, which must be around when the functions actually get applied. There are probably bad interactions with the module system, but I'm not certain. People must have talked about this before... was a consensus reached that I'm not aware of? - Cale On Apr 6, 2005 2:10 AM, Arjun Guha [EMAIL PROTECTED] wrote: This is a contrived example, but contains the essence of what I'd like to do. Suppose I have this datatype: data (Eq v) = EqList v = EqList [v] I'd like to make it an instance of Functor. However, fmap takes an arbitrary function of type a - b. I need an Eq constraint on a and b. Is there any way to do this without creating my own `EqFunctor' class with explicitly-kinded quantification: class (Eq a) = EqFunctor (f :: * - *) a where eqfmap:: (Eq b) = (a - b) - f a - f b Thanks. -Arjun ___ 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
Re: Functional dependencies, principal types, and decidable typechecking
Manuel M T Chakravarty wrote: I accept that this is the process by which GHC computes these types, but it does violate the principal types property, doesn't it? The relation Int - () = forall c. Int - c does not hold. I realise that principal types and principal typings are slightly different, but I was wondering if the fact that it has recently been shown that Hindley/Milner does not have principal typings has any meaning here? Keean. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Oops [Fwd: Re: Allowing duplicate instances in GHC 6.4]
Robert van Herk wrote: Sorry, this is the compiler error I get: No instances for (KeyHasValue MyKeyVal k' v', Datasource.Tools.FakePrelude.TypeEq Float k' z, Datasource' z [MyKeyVal] [MyKeyVal] Float Int) When I am trying to do do { createJoinedDS' x x; (joined,(v::Maybe Int)) - _dsread joined (2.0::Float); } Robert Subject: Re: Allowing duplicate instances in GHC 6.4 From: Robert van Herk [EMAIL PROTECTED] Date: Thu, 31 Mar 2005 16:49:07 +0200 To: glasgow-haskell-users@haskell.org To: glasgow-haskell-users@haskell.org Return-Path: [EMAIL PROTECTED] X-Original-To: [EMAIL PROTECTED] Delivered-To: [EMAIL PROTECTED] Received: from mail.students.cs.uu.nl (localhost.localdomain [127.0.0.1]) by mail.students.cs.uu.nl (Postfix) with ESMTP id 85339225D8C for [EMAIL PROTECTED]; Thu, 31 Mar 2005 16:54:12 +0200 (CEST) Received: from mail.cs.uu.nl (dusk.cs.uu.nl [131.211.80.10]) by mail.students.cs.uu.nl (Postfix) with ESMTP id 68C95225D84 for [EMAIL PROTECTED]; Thu, 31 Mar 2005 16:54:12 +0200 (CEST) Received: by mail.cs.uu.nl (Postfix) id EF0D9A35E2; Thu, 31 Mar 2005 16:54:11 +0200 (CEST) Delivered-To: [EMAIL PROTECTED] Received: from mail.cs.uu.nl (localhost.localdomain [127.0.0.1]) by mail.cs.uu.nl (Postfix) with ESMTP id D9C06A35F7; Thu, 31 Mar 2005 16:54:11 +0200 (CEST) Received: from www.haskell.org (bugs.haskell.org [128.36.229.215]) by mail.cs.uu.nl (Postfix) with ESMTP id 99FA2A35E2; Thu, 31 Mar 2005 16:54:11 +0200 (CEST) Received: from haskell.cs.yale.edu (localhost.localdomain [127.0.0.1]) by www.haskell.org (Postfix) with ESMTP id 666A436825E; Thu, 31 Mar 2005 09:36:48 -0500 (EST) X-Original-To: glasgow-haskell-users@haskell.org Delivered-To: glasgow-haskell-users@haskell.org Received: from mail.cs.uu.nl (dusk.cs.uu.nl [131.211.80.10]) by www.haskell.org (Postfix) with ESMTP id 3A87D368106 for glasgow-haskell-users@haskell.org; Thu, 31 Mar 2005 09:36:45 -0500 (EST) Received: from mail.cs.uu.nl (localhost.localdomain [127.0.0.1]) by mail.cs.uu.nl (Postfix) with ESMTP id 16C67A35F7; Thu, 31 Mar 2005 16:54:05 +0200 (CEST) Received: from [131.211.84.110] (mckroket.labs.cs.uu.nl [131.211.84.110]) by mail.cs.uu.nl (Postfix) with ESMTP id 0635AA35E2; Thu, 31 Mar 2005 16:54:05 +0200 (CEST) Message-ID: [EMAIL PROTECTED] User-Agent: Mozilla Thunderbird 1.0 (Macintosh/20041206) X-Accept-Language: en-us, en MIME-Version: 1.0 References: [EMAIL PROTECTED] [EMAIL PROTECTED] [EMAIL PROTECTED] [EMAIL PROTECTED] [EMAIL PROTECTED] [EMAIL PROTECTED] In-Reply-To: [EMAIL PROTECTED] Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-AV-Checked: ClamAV using ClamSMTP at cs.uu.nl X-BeenThere: glasgow-haskell-users@haskell.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: The Glasgow Haskell Users Mailing List glasgow-haskell-users.haskell.org List-Unsubscribe: http://www.haskell.org/mailman/listinfo/glasgow-haskell-users, mailto:[EMAIL PROTECTED] List-Archive: http://www.haskell.org//pipermail/glasgow-haskell-users List-Post: mailto:glasgow-haskell-users@haskell.org List-Help: mailto:[EMAIL PROTECTED] List-Subscribe: http://www.haskell.org/mailman/listinfo/glasgow-haskell-users, mailto:[EMAIL PROTECTED] Sender: [EMAIL PROTECTED] Errors-To: [EMAIL PROTECTED] X-AV-Checked: ClamAV using ClamSMTP at cs.uu.nl X-AV-Checked: ClamAV using ClamSMTP at students.cs.uu.nl X-Spam-Checker-Version: SpamAssassin 3.0.2-hvl (2004-11-16) on dawn.students.cs.uu.nl X-Spam-Status: No, score=-0.7 required=7.0 tests=AWL autolearn=ham version=3.0.2-hvl Hi Keean, First of all, thank you for your answers. I have tried your solution using TypeEq. instance (Datasource l k' v', TypeEq k k' z, Datasource' z l r k v) = Datasource (JoinedDS l r) k v where _dsread (JoinedDS refl refr) k = do { l - readIORef refl; r - readIORef refr; (z,l,r,v) - _dsread' (l,r) k; writeIORef refl l; writeIORef refr r; return (JoinedDS refl refr, v); } class Datasource' z l r k v | l r k - v where class Datasource' z l r k v | z l r k - v where _dsread' :: (l,r) - k - IO (z,l,r,Maybe v) _dswrite' :: (l,r) - k - v - IO (z,l,r) instance Datasource l k v = Datasource' HTrue l r k v where _dsread' (l,r) k = do { (l,v) - _dsread l k; return (hTrue, l, r, v); } instance Datasource r k v = Datasource' HFalse l r k v where _dsread' (l,r) k = do { (r,v) - _dsread r k; return (hFalse, l, r, v); } This compiles. I cannot, however, include type z in the fundep of Datasource', since this conflicts with Datasource ds k v | ds
Re: Oops [Fwd: Re: Allowing duplicate instances in GHC 6.4]
Some more fixes... Keean Schupke wrote: Hi Keean, First of all, thank you for your answers. I have tried your solution using TypeEq. instance (Datasource l k' v', TypeEq k k' z, Datasource' z l r k v) = Datasource (JoinedDS l r) k v where _dsread (JoinedDS refl refr) k = do { l - readIORef refl; r - readIORef refr; (z,l,r,v) - _dsread' (l,r) k; writeIORef refl l; writeIORef refr r; return (JoinedDS refl refr, v); } _dsread (JoinedDS l r) k = _dsread' (typeEq (undefined::k') k) l r k class Datasource' z l r k v | l r k - v where class Datasource' z l r k v | z l r k - v where _dsread' :: (l,r) - k - IO (z,l,r,Maybe v) _dswrite' :: (l,r) - k - v - IO (z,l,r) instance Datasource l k v = Datasource' HTrue l r k v where _dsread' (l,r) k = do { (l,v) - _dsread l k; return (hTrue, l, r, v); The type says the return type of Datasource' is v where v is the type resturned from _dsread so: _dsread' _ (l,r) k = _dsread l k The types are determined by the instance... (I don't understand why you are trying to return hTrue _dsread :: s - k - v and for Datasource' _dsread :: z - l - r - k - v } instance Datasource r k v = Datasource' HFalse l r k v where _dsread' (l,r) k = do { (r,v) - _dsread r k; return (hFalse, l, r, v); } This compiles. I cannot, however, include type z in the fundep of Datasource', since this conflicts with Datasource ds k v | ds k - v. Furthermore, I do not understand how the key and value types of my right datasource (r k v) is bound to the instance of Datasource (JoinedDS l r) k v, since in the premisse (Datasource l k' v', TypeEq k k' z, Datasource' z l r k v), nothing is said about Datasource r k'' v''. However, I could be wrong in this, since Datasource r k v is in the premisse of instance Datasource r k v = Datsource' HFalse l r k v. However, my problem is, that when I use this code: do {joined - createJoinedDS' x y; (joined,(v::Maybe Int)) - _dsread joined (2.0::Float); } {- | Easy constructor -} createJoinedDS :: (IORef left) - (IORef right) - JoinedDS left right createJoinedDS left right = JoinedDS left right createJoinedDS' :: left - right - IO (JoinedDS left right) createJoinedDS' l r = do { left - newIORef l; right - newIORef r; return (createJoinedDS left right); } the compiler will complain: Could not deduce (Datasource' z1 l r k v) from the context (Datasource (JoinedDS l r) k v, Datasource l k' v', TypeEq k k' z, Datasource' z l r k v) arising from use of `_dsread'' It seems to be the case that it cannot decide on the type of z. See change above! Also note type of fundep for Datasource should now be: class Datasource s k v | s - k v where ... Keean. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Oops [Fwd: Re: Allowing duplicate instances in GHC 6.4]
Not at all... You can have Datasource s k v | s k - v ... but I have't time to do it now... By the way that wasn't the change I was talking about! class Datasource' z l r k v | z l r k - v The 'z' was missing from your fundep. Keean. Robert van Herk wrote: See change above! Also note type of fundep for Datasource should now be: class Datasource s k v | s - k v where ... I see But the cool thing was, that my datasources were generic, in the sence that they could store multiple k's and v's. Now, they would be unique for the actual storage mechanism used, meaning, for example, that I could only read values from 1 table, if I'd instantiate the datasource for a database coupling. Currently, I use the Boilerplate approach to make it possible to store multiple types in one datasource, for example: data MyKeyVal = IntXString Int String | FloatXInt Float Int deriving (Eq, Ord, Show) Furthermore, I generate an instance of KeyHasValue, to tell my framework which keys are valid for a datasource, for example: instance KeyHasValue MyKeyVal Int String where constructor = IntXString instance KeyHasValue MyKeyVal Float Int where constructor = FloatXInt I have an instance instance (..., KeyHasValue a k v) = Datasource [a] k v where ... This way, I can read Ints from a [MyKeyVal], and get a String, and read Floats, and get an Int. If I would have a fundep class Datasource s k v | s - k v where ... this wouldn't be possible anymore, I guess? Regards, Robert ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Oops [Fwd: Re: Allowing duplicate instances in GHC 6.4]
In the case where a datasource is determined by 's' and 'k', we need to return a different type depending on sucess or failure: data TJust t = TJust t data TNothing = TNothing class Datasource s k v | s k - v where dsread :: s - k - v instance (Datasource l k v',Datasource r k v'',Datasource' v' v'' v) = Datasource (JoinedDS l r) k v where dsread (JoinedDS l r) k = dsread' (dsread l k) (dsread r k) class Datasource' l r v | l r - v where dsread' :: l - r - v instance Datasource' TNothing TNothing TNothing where dsread' _ _ = TNothing instance Datasource' (TJust l) TNothing (TJust l) where dsread' t _ = t instance Datasource' TNothing (TJust r) (TJust r) where dsread' _ t = t instance Datasource' (TJust l) (TJust r) TNothing where dsread' _ _ = TNothing Now all you need to do is arrange for individual datasources to return (TJust v) if that combination of source and key exist and TNothing if they dont. Something like: instance Datasource Source1 Key1 (TJust Value1) instance Datasource Source1 Key2 TNothing instance Datasource Source2 Key1 TNothing instance Datasource Source2 Key2 (TJust Value2) This is a simple implementation, using TypeEq, you can generically reject with TNothing all datasource instances not specifically defined. Keean. Hi Keean, First of all, thank you for your answers. I have tried your solution using TypeEq. instance (Datasource l k' v', TypeEq k k' z, Datasource' z l r k v) = Datasource (JoinedDS l r) k v where _dsread (JoinedDS refl refr) k = do { l - readIORef refl; r - readIORef refr; (z,l,r,v) - _dsread' (l,r) k; writeIORef refl l; writeIORef refr r; return (JoinedDS refl refr, v); } class Datasource' z l r k v | l r k - v where _dsread' :: (l,r) - k - IO (z,l,r,Maybe v) _dswrite' :: (l,r) - k - v - IO (z,l,r) instance Datasource l k v = Datasource' HTrue l r k v where _dsread' (l,r) k = do { (l,v) - _dsread l k; return (hTrue, l, r, v); } instance Datasource r k v = Datasource' HFalse l r k v where _dsread' (l,r) k = do { (r,v) - _dsread r k; return (hFalse, l, r, v); } This compiles. I cannot, however, include type z in the fundep of Datasource', since this conflicts with Datasource ds k v | ds k - v. Furthermore, I do not understand how the key and value types of my right datasource (r k v) is bound to the instance of Datasource (JoinedDS l r) k v, since in the premisse (Datasource l k' v', TypeEq k k' z, Datasource' z l r k v), nothing is said about Datasource r k'' v''. However, I could be wrong in this, since Datasource r k v is in the premisse of instance Datasource r k v = Datsource' HFalse l r k v. However, my problem is, that when I use this code: do {joined - createJoinedDS' x y; (joined,(v::Maybe Int)) - _dsread joined (2.0::Float); } {- | Easy constructor -} createJoinedDS :: (IORef left) - (IORef right) - JoinedDS left right createJoinedDS left right = JoinedDS left right createJoinedDS' :: left - right - IO (JoinedDS left right) createJoinedDS' l r = do { left - newIORef l; right - newIORef r; return (createJoinedDS left right); } the compiler will complain: Could not deduce (Datasource' z1 l r k v) from the context (Datasource (JoinedDS l r) k v, Datasource l k' v', TypeEq k k' z, Datasource' z l r k v) arising from use of `_dsread'' It seems to be the case that it cannot decide on the type of z. Would you know how to solve this? Regards, Robert ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: moving from ghc-6.2 to 6.4
Thought I would run some benchmarks with different compiler options, so I pulled out some code (that compiled fine with 6.2). The code uses MArrays to calculate a tree difference between two different XML files. Anyway tying to compile with 6.4 I get: ghc-6.3: panic! (the `impossible' happened, GHC version 6.3): app_match: unbound tpl s{tv a2M9} Please report it as a compiler bug to glasgow-haskell-bugs@haskell.org, Any idea how to track down the cause of this? Keean. Simon Marlow wrote: On 29 March 2005 08:59, Johannes Waldmann wrote: I am trying to bring a larger heap of code (http://141.57.11.163/auto/ ) into 6.4 land (because of wonder stories about faster compilation, faster execution, Data.Map, and so on ...) Here are a few observations and questions that may be useful to others as well. * what is the situation with ghc-6.4 for sparc/solaris? I don't see a binary package in the download area. I started to build from source - can this be successful? (The rest of this report refers to i386/linux) There are some outstanding issues on Sparc/Solaris that I didn't get around to investigating before the release. One of them is a random crash, so you should probably consider 6.4 to be broken on Sparc/Solaris for the time being (it might be related to gcc version though: 6.2.x might be just as broken with recent gcc versions). I'm keen to get more data points, if you have the time inclination to test it. We could really do with a Sparc/GHC guru to take up the mantle of maintaining the Sparc port - it's kind of hard for us to do it without the hardware locally, and I'm no Sparc expert. * Cabal is very nice! - The only thing that was confusing me is that I have to list all modules in the *.cabal file: if I don't, it still happily builds and installs the package but it cannot be used, giving linker errors. Couldn't this be checked earlier? Or better, couldn't it infer the needed hidden modules? Anyway I can generate the module list by a shell script but that does not feel right. - How do I build and install a profiling version of a package, how does Cabal support this? The module list: yes, I think this is something the Cabal team would like to automate in the future. There's no way to build profiled packages at the moment, as far as I'm aware. I agree it's an important feature, though. * I don't see dramatic improvements in execution times - are there some magic ghc options I missed? I used -O -fvia-C. Still, executables are maybe 2 .. 5 % smaller and faster than they were with 6.2 - and compilation without -O is really fast. I don't know where this rumour of dramatic improvements in execution time comes from :-) Our testing shows modest improvements in most programs, with some programs going slower. The focus of 6.4 wasn't really on performance, but we hope to merge performance improvements back into future 6.4 releases. Cheers, Simon ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Allowing duplicate instances in GHC 6.4
Robert van Herk wrote: Hi all, I need to use duplicate instances. I read in the documentation on GHC 6.4, that overlapping class instances checks are lazy instead of gready in 6.4. However, my code still gives duplicate instance errors when compiling in GHC 6.4. Is the duplicate instance check still gready? Is there a way to overwrite that behaviour? Right now, I have two instance of a class Datasource. Datasource allows the user to read (key,value) pairs. class Datasource ds k v where ... Now, I wanted to make a special datasource that combines two datasources, namely data JoinedDS left right = JoinedDS left right instance (Datasource left k v) = Datasource (JoinedDS left right) k v where ... instance (Datasource right k v) = Datasource (JoinedDS left right) k v where ... The idea is that when you combine 2 datasources in one JoinedDS, the user can read both types from the JoinedDS. I do not need to allow to combine 2 different datasources that have the same types of (key,value) pairs, so the duplicate instances will not occur and when they do, this will be by mistake. Hence, the two premisses in the instance declaration will never be fulfilled both at the same time and I do not want a duplicate instance error here. Is there a solution to this problem? To resolve overlap the HEAD of the instance must be different... Might I suggest: -- as value depends on source and key, requires functional dependancy class Datasource s k v | s k - v ... data JoinedDS l r = JoinedDS l r instance (Datasource l k v1,Datasource r k v2) = Datasource (JoinedDS l r) k (v1,v2) ... Now a joined datasource resturns a pair of values instead of a single value. Keean. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Allowing duplicate instances in GHC 6.4
Keean Schupke wrote: Robert van Herk wrote: Hi all, I need to use duplicate instances. I read in the documentation on GHC 6.4, that overlapping class instances checks are lazy instead of gready in 6.4. However, my code still gives duplicate instance errors when compiling in GHC 6.4. Is the duplicate instance check still gready? Is there a way to overwrite that behaviour? Right now, I have two instance of a class Datasource. Datasource allows the user to read (key,value) pairs. class Datasource ds k v where ... Now, I wanted to make a special datasource that combines two datasources, namely data JoinedDS left right = JoinedDS left right instance (Datasource left k v) = Datasource (JoinedDS left right) k v where ... instance (Datasource right k v) = Datasource (JoinedDS left right) k v where ... The idea is that when you combine 2 datasources in one JoinedDS, the user can read both types from the JoinedDS. I do not need to allow to combine 2 different datasources that have the same types of (key,value) pairs, so the duplicate instances will not occur and when they do, this will be by mistake. Hence, the two premisses in the instance declaration will never be fulfilled both at the same time and I do not want a duplicate instance error here. Is there a solution to this problem? To resolve overlap the HEAD of the instance must be different... Might I suggest: -- as value depends on source and key, requires functional dependancy class Datasource s k v | s k - v ... data JoinedDS l r = JoinedDS l r instance (Datasource l k v1,Datasource r k v2) = Datasource (JoinedDS l r) k (v1,v2) ... Now a joined datasource resturns a pair of values instead of a single value. Further to this to get the exact behaviour you want, if a datasource can return the result using a type lifted maybe on a lookup failure then: class Datasource s k v | s k - v ... data JoinedDS l r = JoinedDS l r instance (Datasource l k v1, Datasource r k v2, JoinDS v1 v2 v) = Datasource (JoinedDS l r) k v class Fail data This_should_never_happen data TNothing = TNothing data TJust a = TJust a class JoinDS l r t | l r - t instance JoinDS TNothing TNothing TNothing instance JoinDS TNothing (TJust v) (TJust v) instance JoinDS (TJust u) TNothing (TJust u) instance Fail This_should_never_happen = JoinDS (TJust u) (TJust v) TNothing Now you datasources just need to return the type TJust v on success and TNothing on failure. Keean. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Allowing duplicate instances in GHC 6.4
There was a typo in the code I posted: class Fail data This_should_never_happen should read: class Fail x data This_should_never_happen Keean. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Allowing duplicate instances in GHC 6.4
Just thought I ought to point out that all this is only necessary if the datasources may return different types... If you want them to return the same type you only need: instance (Datasource l k v,Datasource r k v) = Datasource (JoinedDS l r) k v ... As both datasources have the same key and value types, you then choose which 'v' to return at the value level. I am not sure whether you intended Datasources to contain heterogeneous key or value types, and whether the loolup is supposed to be value or type driven. My original answer assumed a single Datasource contains values of different types, selected by the type of the key... Keean. Robert van Herk wrote: Yes, but this is not what I want. I want to be able to give a key that either the left or the right data source would take, and then return the appropriate value. Thus: if I pass it a key that would normally go into l, I want the value l returns me to be returned, and if I pass it the key that would normally go into r, I want to return the value r returns me. The datasource class has a function dsread :: ds - k - (ds, v) -- read may have a side effect Thus I want want to do something like: instance (Datasource l k v) = Datasource (JoinedDS l r) k v where dsread (JoinedDS l r) k = let (l, v) = dsread l k in (JoinedDS l r, v) instance (Datasource r k v) = Datasource (JoinedDS l r) k v where dsread (JoinedDS l r) k = let (r, v) = dsread r k in (JoinedDS l r, v) It would be perfectly okay to me when the compiler would complain if the key and value that go into l and r are the same, but for any useful purpose I can think of (e.g. glueing two database couplings together, since I also made a Datasource instance for database access), this will not happen and the duplicate instances should not really occur, since the context of the instances makes sure only 1 will be possible. However, GHC only looks at the RHS (thus: Datasource (JoinedDS l r) k v) and then decides that both instances are the same. So, my question was: how to overcome this. Thanks, Robert ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Allowing duplicate instances in GHC 6.4
Robert van Herk wrote: Keean Schupke wrote: Just thought I ought to point out that all this is only necessary if the datasources may return different types... If you want them to return the same type you only need: instance (Datasource l k v,Datasource r k v) = Datasource (JoinedDS l r) k v ... As both datasources have the same key and value types, you then choose which 'v' to return at the value level. Nono, the datasources I have implemented are a type safe means to extract (key,value) pairs from a data store. The idea is that this way, in a type safe fashion, e.g. database access can be abstract. I use HaskellDB as the database access layer, and then define a datasource instance for any given database, so that the user does not need to think about the details of the actual database access: he can just read and write from the datasource, and the datasource will make sure the actual queries will be executed. My idea now was that if I have 2 databases, and I construct datasources for them, it would be really cool if I was able to unite them, so that the programmer in the end could talk two 1 datasource, that allowed for accessing the 2 databases at one entry point. This was what I was making the JoinedDS for. So, suppose I have 2 datasources for two different databases. One may have keys: data KeysOfDS1 = KDB1_Table1 Int | KDB1_Table2 Int and values data ValuesOfDS1 = VDB1_Table1 (Int,Int,String) | VDB2_Table2 (Int,Int,String) and the other one: data KeysOfDS2 = KDB2_Table1 String | KDB2_Table2 String data ValuesOfDS2 = VDB2_Table1 (String, Float) | VDB2_Table2 (String, Float, Int) Now, these datastructures correspond to the actual tables in the database. My toolset will generate datasources for these types, thus we have instances: instance Datasource Database1 KeysOfDS1 ValuesOfDS1 instance Datasource Database2 KeysOfDS2 ValuesOfDS2 and the cool thing would be, to combine these two datasources at a higher level in my datasources graph, so that I would have 1 datasource that found out by itself which actual datasource to use, thus: x::JoinedDS x = JoinedDS db1 db2 -- where dbx is a datasource Databasex KeysOfDSx ValuesOfDSx Now, I would want the user to be able to read both KeysOfDS1 (which would yield a ValuesOfDS1) as well as KeysOfDS2 (which would yield a ValuesOfDS2) from x. Herefore, I need the instances mentioned before: instance (Datasource l k v) = Datasource (JoinedDS l r) k v where dsread (JoinedDS l r) k = let (l, v) = dsread l k in (JoinedDS l r, v) instance (Datasource r k v) = Datasource (JoinedDS l r) k v where dsread (JoinedDS l r) k = let (r, v) = dsread r k in (JoinedDS l r, v) But this, thus, yields duplicate instance errors, which I don't like :-). Robert P.S. Sorry for any typos, I am enjoying a rather nice bottle of wine :-). Thats because they overlap in 'k'. However you can change the fundep: class Datasource s k v | s - k v instance Datasource DB1 K1 V1 instance Datasource DB2 K2 V2 instance (Datasource l k' v',TypeEq k k' z,Datasource' z l r k v) = Datasource (JoinedDS l r) k v where class Datasource' z l r k v | z l r - k v instance Datasource l k v = Datasource' TTrue l r k v instance Datasource r k v = Datasource' TFalse l r k v Here I have used TypeEq from the HList library to determine if the type parameter k is the same type as the k' from datasource l. This lets k determine which instance from the other class gets used. Keean. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: [Haskell] Haskell 6.4 perfomance
Think this should really go to glasgow-haskell-users... If this is true - how do I get ghc to use C--, and is it really faster than using gcc as a backend with all the bells whistles turned on (for a pentium-III) something like -O3 -mcpu=pentium3 -march=pentium3 -pipe -fomit-frame-pointer -momit-leaf-frame-pointer -ftracer -fno-crossjumping -mfpmath=sse,387 -ffast-math -fsched-spec-load -fprefetch-loop-arrays -maccumulate-outgoing-args -fmove-all-movables -freduce-all-givs Keean. Alexandre wrote: As I heard, 6.4 version of the Haskell using C-- backend and make lots of the resulting code perfomance (programs executed faster). If so, does any test/comparison with other languages available? Thank you in advance, Regards, /Alexandre. ___ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: [Haskell] The FunctorM library
Why not just have the new definition with a different import path, so that legacy code continues to do: import Control.Monad And new code could do: import Control.Category.Monad (or something) And we could take this opportunity to incorporate premonads... class Functor f -- defines fmap class Functor p = Premonad p -- defines return class Premonad m = Monad m -- defines bind Keean. Simon Peyton-Jones wrote: | Yes, I think this should be fixed, and perhaps it could be done in a | backward compatible way? If classes were allowed to declare default | methods for superclasses, then you could have | | class Functor f where fmap :: ... | class Functor m = Monad m where | ...the usual stuff... | fmap = liftM | | Then declaring | | instance Monad T where ... | | for some T, would implicitly introduce an instance Functor T, if it is | not defined explicitly... It seems overkill to have a whole new language feature to deal with one library issue. It would take a bit of implementing too, and it's not clear to me what the specification is. For example, what if Functor T *is* defined explicitly, but in a later module? The idea comes up very occasionally, but I wouldn't say it's been a hot issue. Simon ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell] Haskell 6.4 perfomance
Think this should really go to glasgow-haskell-users... If this is true - how do I get ghc to use C--, and is it really faster than using gcc as a backend with all the bells whistles turned on (for a pentium-III) something like -O3 -mcpu=pentium3 -march=pentium3 -pipe -fomit-frame-pointer -momit-leaf-frame-pointer -ftracer -fno-crossjumping -mfpmath=sse,387 -ffast-math -fsched-spec-load -fprefetch-loop-arrays -maccumulate-outgoing-args -fmove-all-movables -freduce-all-givs Keean. Alexandre wrote: As I heard, 6.4 version of the Haskell using C-- backend and make lots of the resulting code perfomance (programs executed faster). If so, does any test/comparison with other languages available? Thank you in advance, Regards, /Alexandre. ___ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Re: [Haskell-cafe] Linux device drivers
Actually with PCI chipsets, implementing a generic BusMaster DMA driver is not too hard, assuming you already have interrupts handled (and you don't want 64bit DMA support)... You just load the parameters for the disk read into the PCI registers, and wait for the completed interrupt. I wrote a diver in assembly language for my own OS project a few years ago. Keean. Iavor Diatchki wrote: Hello, There are no storage drivers at the moment. Actually part of the motivation for implementing the networking stuff was so that we can avoid doing that at least for the time being. -Iavor On Mon, 21 Mar 2005 01:32:19 -0500 (Eastern Standard Time), S. Alexander Jacobson [EMAIL PROTECTED] wrote: Very very cool. Has anyone written any storage drivers? If there is already TCP, has someone written an iscsi (RFC3720) driver? -Alex- On Mon, 21 Mar 2005, Donald Bruce Stewart wrote: dons: alex: Wow! Did you also implement tcp in Haskell? On this topic, the following House code looks relevant: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/programatica/hOp/kernel/Net/ There's something satsifying about seeing 'instance Functor Packet' in IPv4.hs ;) Does hOp or House also have the ability to write to disk? (With HAppS, I've gotten rid of the AMP part of LAMP, it would be really cool to get rid of the L as well!) Sorry! By We've got a few drivers written in Haskell, I meant the Haskell community, not me personally :} You have the hOp and House developers to thank for this stuff. On Mon, 21 Mar 2005, Donald Bruce Stewart wrote: mark: I was wondering about the possibility of using Haskell for developing device drivers that would be kernel modules for Linux. If nothing else, it would be quite an educational experience for me, as I've not yet experimented with either the Linux kernel or Haskell FFI, nor have I had to learn how to squeeze much performance out of my Haskell code. Clearly, this application demands special things from the compiler and the runtime. But, I'm not exactly sure what, nor how to achieve such given current compilers. Does anyone have any thoughts? Well, it would be tricky, but fun! We've got a few drivers written in Haskell already (but not for Linux, as far as I know). For example check out the House network stack and drivers: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/programatica/hOp/ and http://cvs.haskell.org/cgi-bin/cvsweb.cgi/programatica/hOp/kernel/Kernel/Driver/NE2000/ So there's heavy use of Data.Bits and Word# types - but nothing that isn't fairly well established in GHC Haskell, anyway. Then (for GHC, anyway) you'd have to link the kernel against libHSrts.a, much as we do when calling Haskell from other kinds of C apps, which involves compiling the C app with all the magic flags ghc normally sets up (ghc -v9 main.c is helpful). Something like: ;) egcc -v -o a.out -DDONT_WANT_WIN32_DLL_SUPPORT main.o -L/home/dons/lib/ghc-6.4 -lHStemplate-haskell -lHSCabal -lHSposix -lHSposix_cbits -lHSlang -lHSmtl -lHShaskell-src -lHSunix -lHSunix_cbits -lHShi -lHShaskell98 -lHSaltdata -lHSbase -lHSbase_cbits -lHSrts -lm -lgmp -u GHCziBase_Izh_static_info -u GHCziBase_Czh_static_info -u GHCziFloat_Fzh_static_info ... Then, having the kernel start up the Haskell rts (at boot would be good): hs_init(argc, argv); .. do something in Haskell or C land ... hs_exit(); Then you'd could dyn load (via GHC's rts) your Haskell driver into the C app, and use it, as long as you've got a nice ffi interface to pass values back and forward. I'm sure the fun part is in the details ;) Cheers, Don ___ 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 __ S. Alexander Jacobson tel:917-770-6565 http://alexjacobson.com ___ 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
Re: [Haskell-cafe] Linux device drivers
I thought the BusMaster interface was pretty uniform, unlike the earlier DMA interfaces which varied from chipset to chipset. Keean. Lennart Augustsson wrote: But there are plenty of minor variations on how to program and initiate DMA for different devices. -- Lennart Keean Schupke wrote: Actually with PCI chipsets, implementing a generic BusMaster DMA driver is not too hard, assuming you already have interrupts handled (and you don't want 64bit DMA support)... You just load the parameters for the disk read into the PCI registers, and wait for the completed interrupt. I wrote a diver in assembly language for my own OS project a few years ago. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] tuple and HList
Oleg has just pointed out that the 'Show' constraint bellow does not work if you try and use a function from the show class (say 'show'), as the function: test2 l = show l has the type: test2 :: forall a. (Show a) = a - String The technique below works to constrain for membership of a class, So we know all elements in the list are instances of show, but we cannot call functions. The best thing here is to let the compiler infer any remaining constraints using: showList :: ConstrainedList SHOW l = l - String showList = undefined test l | False = showList l | otherwise = show (hHead l) Here the 'False' guard is never executed, but its type is unified with the inferred type for 'show l'... ghci shows us: *Main :type test test :: forall b a. (Show a, ConstrainedList SHOW (HCons a b)) = HCons a b - String In other words use constraints only to enforce explicit requirements, the compiler can safely infer all required constraints from the code (IE just don't give signatures for the functions). Keean. Keean Schupke wrote: You can avoid the need to declare a new class for each constrained list by using the following: class Constraint c a data SHOW instance Show a = Constraint SHOW a class HListConstraint c l instance HListConstraint c HNil instance (Constraint c a,HListConstraint c l) = HListConstraint c (HCons a l) You can now constrain a list as follows: assertShow :: HListConstraint SHOW l = l - l assertShow = id The type parameter can be made first class using: showConstraint :: SHOW showConstraint = undefined So we can now pass this as a parameter: assertConstraintOnHList :: HListConstraint c l = c - l - l assertConstraintOnHList _ = id ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Linux device drivers
Have a look at the linux kernel IDE drivers, look for Generic IDE Chipset support Generic PCI bus-master DMA support Keean. Lennart Augustsson wrote: What is this standard BusMaster interface you talk about? I must have missed something. I've yet to see two PCI chips that do DMA the same way. -- Lennart Keean Schupke wrote: I thought the BusMaster interface was pretty uniform, unlike the earlier DMA interfaces which varied from chipset to chipset. Keean. Lennart Augustsson wrote: But there are plenty of minor variations on how to program and initiate DMA for different devices. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Linux device drivers
The generic busmaster diver should go all the way to UDMA mode 4 (133Mb) Keean. Lennart Augustsson wrote: Keean Schupke wrote: Have a look at the linux kernel IDE drivers, look for Generic IDE Chipset support That's the part I missed, you were talking about IDE chips. Yes, they have many similarities. You can probably run many of them in one of the slower modes with a common driver. But even these chips differ in the details. -- Lennart ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Linux device drivers
I don't think I said anything controversial. I guess I was just over-simplifying things by only considering PC IDE hardware - but then again that must get you running on 90% of the systems people are likely to have lying around to play with a developmental OS on. On the other hand the average network driver seems to be about 2,000 lines of code, whereas if you add all the parts of the generic ide driver together you get about 20,000 lines of code. I guess that answers my question - storage is an order of magnitude harder than networking, even before including SCSI. Regards, Keean. Simon Marlow wrote: Keean, you should be aware that Lennart is something of a device driver guru. He knows what he's talking about :-) Go grep for Augustsson in the NetBSD kernel sometime. Cheers, Simon ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] tuple and HList
David Menendez wrote: instance Functor ((,) a) where fmap f (x,y) = (x, f y) If we get rid of '(,)' and redefine '(a,b)' as sugar for 'TCons a (TCons b HNil)' (or whatever), then there is no way to declare the above instance. I don't think that's a deal-killer, but it is a disadvantage. You need to swap the arguments to TCons... data TCons l a = TCons !l a Then: instance Functor (TCons (TCons HNil a)) where fmap f (TCons (TCons HNil x) y) = TCons (TCons HNil (f x)) y) Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] invalid character encoding
One thing I don't like about this automatic conversion is that it is hidden magic - and could catch people out. Let's say I don't want to use it... How can I do the following (ie what are the new API calls): Open a file with a name that is invalid in the current locale (say a zip disc from a computer with a different locale setting). Open a file with contents in an unknown encoding. What are the new binary API calls for file IO? What type is returned from 'getChar' on a binary file. Should it even be called getChar? what about getWord8 (getWord16, getWord32 etc...) Does the encoding translation occur just on the filename or the contents as well? What if I have an encoded filename with binary contents and vice-versa. Keean. (I guess I now have to rewrite a lot of file IO code!) ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] tuple and HList
Frederik Eaton wrote: Another thing which I don't think is mentioned in the paper, which is convenient, is that you can define HLists all of whose elements are members of a given class: class HListShow l instance HListShow HNil instance (Show a, HListShow l) = HListShow (a :* l) You can avoid the need to declare a new class for each constrained list by using the following: class Constraint c a data SHOW instance Show a = Constraint SHOW a class HListConstraint c l instance HListConstraint c HNil instance (Constraint c a,HListConstraint c l) = HListConstraint c (HCons a l) You can now constrain a list as follows: assertShow :: HListConstraint SHOW l = l - l assertShow = id The type parameter can be made first class using: showConstraint :: SHOW showConstraint = undefined So we can now pass this as a parameter: assertConstraintOnHList :: HListConstraint c l = c - l - l assertConstraintOnHList _ = id Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] tuple and HList
Frederik Eaton wrote: That's a neat technique. Since it's so general it would be nice if there were a way to make it more automatic, could one use template haskell? It seems one should be able to write HListConstraint $(mkConstraint Show) l to generate the declarations automatically. Frederik This is planned as part of a template-haskell library allowing automatic lifting of data types to classes. This would most likely be written: $(ttypelift [d| type ShowList = [Show] |]) or for a function $(ttypelift [d| f :: [Show] - [Show] |] (Here Show is assumed to be defined as a type in the environment) Lifting a list of type [Show] produces an HList where each element is constrained to be an instance of the class Show. If we consider type level naturals we can define a list [HNat] where each element is a type level natural number. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] invalid character encoding
David Roundy wrote: That's not true, there could be many filesystems, each of which uses a different encoding for the filenames. In the case of removable media, this scenario isn't even unlikely. I agree - I can quite easily see the situation occuring where a student (say from japan) brings in a zip-disk or USB key formatted with a japanese filename encoding, that I need to read on my computer (with a UK locale). Also can different windows have different encodings? I might have a web browser (written in haskell?) running and have windows with several different encodings open at the same time, whist saving things on filesystems with differing encodings. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] invalid character encoding
I cannot help feeling that all this multi-language support is a mess. All strings should be coded in a universal encoding (like UTF8) so that the code for a character is the same independant of locale. It seems stupid that the locale affects the character encodings... the code for an 'a' should be the same all over the world... as should the code for a particular japanese character. In other words the locale should have no affect on character encodings, it should select between multi-lingual error messages which are supplied as distinct strings for each region. While we may have to inter-operate with 'C' code, we could have a Haskell library that does things properly. Keean. Marcin 'Qrczak' Kowalczyk wrote: Glynn Clements [EMAIL PROTECTED] writes: The (non-wchar) curses API functions take byte strings (char*), so the Haskell bindings should take CString or [Word8] arguments. Programmers will not want to use such interface. When they want to display a string, it will be in Haskell String type. And it prevents having a single Haskell interface which uses either the narrow or wide version of curses interface, depending on what is available. If you provide wrapper functions which take String arguments, either they should have an encoding argument or the encoding should be a mutable per-terminal setting. There is already a mutable setting. It's called locale. I don't know enough about the wchar version of curses to comment on that. It uses wcsrtombs or eqiuvalents to display characters. And the reverse to interpret keystrokes. It is possible for curses to be used with a terminal which doesn't use the locale's encoding. No, it will break under the new wide character curses API, and it will confuse programs which use the old narrow character API. The user (or the administrator) is responsible for matching the locale encoding with the terminal encoding. Also, it's quite common to use non-standard encodings with terminals (e.g. codepage 437, which has graphic characters beyond the ACS_* set which terminfo understands). curses don't support that. The locale encoding is the right encoding to use for conversion of the result of strerror, gai_strerror, msg member of gzip compressor state etc. When an I/O error occurs and the error code is translated to a Haskell exception and then shown to the user, why would the application need to specify the encoding and how? Because the application may be using multiple locales/encodings. But strerror always returns messages in the locale encoding. Just like Gtk+2 always accepts texts in UTF-8. For compatibility the default locale is C, but new programs which are prepared for I18N should do setlocale(LC_CTYPE, ) and setlocale(LC_MESSAGES, ). There are places where the encoding is settable independently, or stored explicitly. For them Haskell should have withCString / peekCString / etc. with an explicit encoding. And there are places which use the locale encoding instead of having a separate switch. [The most common example is printf(%f). You need to use the C locale (decimal point) for machine-readable text but the user's locale (locale-specific decimal separator) for human-readable text. This is a different thing, and it is what IMHO C did wrong. This isn't directly related to encodings per se, but a good example of why parameters are preferable to state.] The LC_* environment variables are the parameters for the encoding. There is no other convention to pass the encoding to be used for textual output to stdout for example. C libraries which use the locale do so as a last resort. No, they do it by default. The only reason that the C locale mechanism isn't a major nuisance is that you can largely ignore it altogether. Then how would a Haskell program know what encoding to use for stdout messages? How would it know how to interpret filenames for graphical display? Do you want to invent a separate mechanism for communicating that, so that an administrator has to set up a dozen of environment variables and teach each program separately about the encoding it should assume by default? We had this mess 10 years ago, and parts of it are still alive until today - you must sometimes configure xterm or Emacs separately, but it's being more common that programs know to use the system-supplied setting and don't have to be configured separately. Code which requires real I18N can use other mechanisms, and code which doesn't require any I18N can just pass byte strings around and leave encoding issues to code which actually has enough context to handle them correctly. Haskell can't just pass byte strings around without turning the Unicode support into a joke (which it is now). ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: Best practices for modular programming in Haskell
Yes. Its actually very easy once you get how instance resolution occurs and how constraints work. I have used this style to code a database interface, and am using the OOHaskell style (which is related to this kind of stuff) for an application server (was a SOAP server, but might migrate to the new WebServices standards). Infact there is only one real limitation, and that is you cannot (easily) lift an arbitrary IO value to a type. (You can do this but there must be a limit to the value). This does seem solvable however - but not with the current ghc/hugs architecture. To lift a value to a type the code depending on that type cannot be compiled/type-checked until the value is known. This would be ideally suited to a JIT compiler. Keean. Benjamin Pierce wrote: Actually Haskell fully matches the module system of OCaml -- and then adds some. Haskell provides both generative and applicative (recursive) functors. The following two messages elucidate the correspondence http://www.haskell.org/pipermail/haskell/2004-August/014463.html http://www.haskell.org/pipermail/haskell/2004-September/014515.html Wow. Do people actually develop significant bodies of code in this style? - Benjamin ___ 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
Re: [Haskell-cafe] Joy Combinators (Occurs check: infinite type)
Greg Buchholz wrote: Wow. Color me impressed. A little under a week ago, I stumbled onto Joy, and thought to myself that it could be translated almost directly into Haskell (which would imply it was possible to statically type). Well, it wasn't quite as direct as I had initially thought, but it looks like you've done it. Are there any papers/books out there which I could study to learn more about these (and other) tricks of the type system wizards? Here's a cleaned up version, I have made the function composition and stack both use HLists... a bit neater. Have also added primrec and a 5th factorial. As for type tricks most of these should be in the HList or OOHaskell papers. The things to notice are using types as instance labels, that constraints form horn clause compile time meta-programs (in a non-backtracking prolog style) and that multi-parameter classes with functional depandencies simulate some dependant types. Keean. {-# OPTIONS -fglasgow-exts #-} {-# OPTIONS -fallow-overlapping-instances #-} {-# OPTIONS -fallow-undecidable-instances #-} --Joy implemented in Haskell... extensible embedded language... module Joy where import MainGhcGeneric1 -- Building non-empty lists type HOne = HSucc HZero hOne :: HOne hOne = undefined type HTwo = HSucc HOne hTwo :: HTwo hTwo = undefined type HThree = HSucc HTwo hThree :: HThree hThree = undefined end :: HNil end = hNil instance HList s = Apply HNil s s where apply _ s = s instance (HList s,HList s',HList l,Apply a s s',Apply l s' s'') = Apply (HCons a l) s s'' where apply (HCons a l) s = apply l (apply a s :: s') instance HList s = Apply HZero s (HCons HZero s) where apply _ s = hCons hZero s instance (HNat a,HList s) = Apply (HSucc a) s (HCons (HSucc a) s) where apply a s = hCons a s data Lit a = Lit a lit :: a - Lit a lit a = Lit a unl :: Lit a - a unl (Lit a) = a instance Show a = Show (Lit a) where showsPrec _ (Lit a) = showChar '[' . shows a . showChar ']' instance HList s = Apply (Lit a) s (HCons a s) where apply (Lit a) s = hCons a s class (HBool b,HList s) = HIfte b t f s s' | b t f s - s' where hIfte :: b - t - f - s - s' instance (HList s,Apply t s s') = HIfte HTrue t f s s' where hIfte _ t _ s = apply t s instance (HList s,Apply f s s') = HIfte HFalse t f s s' where hIfte _ _ f s = apply f s data Ifte ifte :: Ifte ifte = undefined instance Show Ifte where showsPrec _ _ = showString If instance (Apply b s r,HHead r b',HIfte b' t f s s') = Apply Ifte (f :*: t :*: b :*: s) s' where apply _ (HCons f (HCons t (HCons b s))) = hIfte (hHead (apply b s :: r) :: b') t f s data Nul nul :: Nul nul = undefined instance Show Nul where showsPrec _ _ = showString Nul instance HList s = Apply Nul (HCons HZero s) (HCons HTrue s) where apply _ (HCons _ s) = hCons hTrue s instance HList s = Apply Nul (HCons (HSucc n) s) (HCons HFalse s) where apply _ (HCons _ s) = hCons hFalse s data EQ eq :: EQ eq = undefined instance Show EQ where showsPrec _ _ = showString Eq instance (HList s,TypeEq a b t) = Apply EQ (HCons a (HCons b s)) (HCons t s) where apply _ (HCons a (HCons b s)) = hCons (typeEq a b) s data Dip dip :: Dip dip = undefined instance Show Dip where showsPrec _ _ = showString Dip instance (HList s,HList s',Apply a s s') = Apply Dip (HCons a (HCons b s)) (HCons b s') where apply _ (HCons a (HCons b s)) = hCons b (apply a s) data Dup dup :: Dup dup = undefined instance Show Dup where showsPrec _ _ = showString Dup instance HList s = Apply Dup (HCons a s) (HCons a (HCons a s)) where apply _ s@(HCons a _) = hCons a s data Pop pop :: Pop pop = undefined instance Show Pop where showsPrec _ _ = showString Pop instance HList s = Apply Pop (HCons a s) s where apply _ (HCons _ s) = s data Swap swap :: Swap swap = undefined instance Show Swap where showsPrec _ _ = showString Swap instance HList s = Apply Swap (HCons a (HCons b s)) (HCons b (HCons a s)) where apply _ (HCons a (HCons b s)) = hCons b (hCons a s) data Suc suc :: Suc suc = undefined instance Show Suc where showsPrec _ _ = showString Suc instance (HNat a,HList s) = Apply Suc (HCons a s) (HCons (HSucc a) s) where apply _ (HCons _ s) = hCons (undefined::HSucc a) s data Pre pre :: Pre pre = undefined instance Show Pre where showsPrec _ _ = showString Pre instance (HNat a,HList s) = Apply Pre (HCons (HSucc a) s) (HCons a s) where apply _ (HCons _ s) = hCons (undefined::a) s data Add add :: Add add = undefined instance Show Add where showsPrec _ _ = showString Add instance (HList s,HAdd a b c) = Apply Add (HCons a (HCons b s)) (HCons c s) where apply _ (HCons _ (HCons _ s)) = hCons (hAdd (undefined::a) (undefined::b)) s class (HNat a,HNat b) = HAdd a b c | a b - c where hAdd :: a - b - c instance HAdd HZero HZero HZero where hAdd _ _ = hZero instance HNat b = HAdd HZero (HSucc b) (HSucc b) where hAdd _ b = b instance HNat a = HAdd (HSucc a) HZero (HSucc a) where hAdd a _ = a instance (HNat (HSucc a),HNat (HSucc b),HNat c,HAdd a b c) = HAdd
Re: [Haskell-cafe] Joy Combinators (Occurs check: infinite type)
Greg Buchholz wrote: Keean Schupke wrote: I dont see why this is illegal... what do we want? take the top two items from the stack? With the code below (direct translation from tuples to HLists) I still get an occurs check error when trying to define fact5... Okay the reason is that types in the code end up depending on values. The type of the stack changes when items are pushed or popped. So the type of the stack returned from recursive functions depends on the recursion count... Haskell is not dependantly typed, so cannot deal with types that depend on values. This is why your code with tuples, and the HList code (which is really doing the same thing through a defined API) both fall down on the recursion. One solution is to make all elements the same type and use lists... like: data Elem = ElemInt Int | ElemChar Char... But this looses any static type checking. The alternative is to lift the values to the type level, using something like Peano numbers to represent naturals: data HZero = HZero data HSucc x = HSucc x Now different values have explictly different types, so we can have types which depend on them... Attached is an example implementation of times using this technique and the HList library (its not debugged... so there might be some mistakes). Keean. {-# OPTIONS -fglasgow-exts #-} {-# OPTIONS -fallow-overlapping-instances #-} {-# OPTIONS -fallow-undecidable-instances #-} module Joy where import MainGhcGeneric1 data Lit a = Lit a instance Apply (Lit a) s (HCons a s) where apply (Lit a) s = HCons a s data If = If instance Apply t s s' = Apply If (HCons f (HCons t (HCons HTrue s))) s' where apply _ (HCons _ (HCons t (HCons _ s))) = apply t s instance Apply f s s' = Apply If (HCons f (HCons t (HCons HFalse s))) s' where apply _ (HCons f (HCons _ (HCons _ s))) = apply f s data Eq = Eq instance TypeEq a b t = Apply Eq (HCons a (HCons b s)) (HCons t s) where apply _ (HCons a (HCons b s)) = HCons (typeEq a b) s data Dip = Dip instance Apply a s s' = Apply Dip (HCons a (HCons b s)) (HCons b s') where apply _ (HCons a (HCons b s)) = HCons b (apply a s) data Dup = Dup instance Apply Dup (HCons a s) (HCons a (HCons a s)) where apply _ s@(HCons a _) = HCons a s data Pop = Pop instance Apply Pop (HCons a s) s where apply _ (HCons _ s) = s data Swap = Swap instance Apply Swap (HCons a (HCons b s)) (HCons b (HCons a s)) where apply _ (HCons a (HCons b s)) = HCons b (HCons a s) class (HNat a,HNat b) = HAdd a b c | a - b - c where hadd :: a - b - c instance HAdd HZero HZero HZero where hadd _ _ = hZero instance HAdd HZero (HSucc b) (HSucc b) where hadd _ b = b instance HAdd a b c = HAdd (HSucc a) (HSucc b) (HSucc (HSucc c)) hadd _ _ = hadd (undefined::a) (undefined::b) data Add = Add instance HAdd a b c = Apply Add (HCons a (HCons b s)) (HCons c s) where apply _ (HCons _ (HCons _ s)) = HCons (hadd (undefined::a) (undefined::b)) s data Mult = Mult instance HMult a b c = Apply Mult (HCons a (HCons b s)) (HCons c s) where apply _ (HCons _ (HCons _ s)) = HCons (hadd (undefined::a) (undefined::b)) s data a @ b = a @ b instance (Apply a s s',Apply b s' s'') = Apply (a @ b) s'' where apply (O a b) s = apply b (apply a s :: s') type Square = Dup @ Mult type Cube = Dup @ Dup @ Mult data I = I instance Apply a s s' = Apply I (HCons a s) s' where apply _ (HCons a s) = apply a s data Times = Times instance Apply Times (HCons p (HCons HZero s)) s where apply _ (HCons _ s) = s instance Apply p s s' = Apply Times (HCons p (HCons (HSucc n) s) (HCons p (HCons n s')) where apply _ (HCons p (HCons _ s)) = HCons p (HCons (undefined::n) (apply p s)) ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe