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
[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
[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-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: [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
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-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: [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
Re: [Haskell-cafe] Joy Combinators (Occurs check: infinite type)
Greg Buchholz wrote: Keean Schupke wrote: Haskell is not dependantly typed, so cannot deal with types that depend on values. Can anyone recommend a nice dependently typed language to play with? Cayenne, Epigram, other? I have refactored your code into a type level Haskell program. This has the nice advantage that it is extensible. You can add a new primitive to the language as: data PrimName primName :: PrimName primName = undefined instance Apply PrimName a b where apply _ a = {- method implementing primName -} Programs are assembled as types like: fac4 = lit nul `o` lit suc `o` lit (dup `o` pre) `o` lit mult `o` linrec Recursion requires a primitive to aviod infinite types, see definitions of times, linrec and genrec. programs are run by applying the contructed type representing the program to a stack... for example: putStrLn $ show $ apply (lit hThree `o` fac4) hNil We could have written this: putStrLn $ show $ apply fac4 (hCons hThree hNil) I have attached the debugged code, simply load into ghci, in the same directory as the HList library (download http://www.cwi.nl/~ralf/HList) as Joy.hs. ghci -fallow-overlapping-instances Joy.hs (you need the flag to get the code to run interactively, however you dont need the flag just to run 'main' to perform the factorial tests) Keean. {-# OPTIONS -fglasgow-exts #-} {-# OPTIONS -fallow-overlapping-instances #-} {-# OPTIONS -fallow-undecidable-instances #-} module Joy where import MainGhcGeneric1 type HOne = HSucc HZero hOne :: HOne hOne = undefined type HTwo = HSucc HOne hTwo :: HTwo hTwo = undefined type HThree = HSucc HTwo hThree :: HThree hThree = undefined data Lit a lit :: a - Lit a lit = undefined unl :: Lit a - a unl = undefined instance HList s = Apply (Lit a) s (HCons a s) where apply a s = hCons (unl 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 (Apply b s r,HHead r b',HIfte b' t f s s') = Apply Ifte (HCons f (HCons t (HCons 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 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 (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 (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 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 HList s = Apply Pop (HCons a s) s where apply _ (HCons _ s) = s data Swap swap :: Swap swap = undefined 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 (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 (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 (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 (HSucc a) (HSucc b) (HSucc (HSucc c)) where hAdd _ _ = hSucc $ hSucc $ hAdd (undefined::a) (undefined::b) data Sub sub :: Sub sub = undefined instance (HList s,HSub a b c) = Apply Sub (HCons b (HCons a s)) (HCons c s) where apply _ (HCons _ (HCons _ s)) = hCons (hSub (undefined::a) (undefined::b)) s class (HNat a,HNat b) = HSub a b c | a b - c where hSub :: a - b - c instance HSub HZero HZero HZero where hSub _ _ = hZero instance HNat a = HSub (HSucc a) HZero (HSucc a) where hSub a _ = a instance HNat a = HSub HZero (HSucc a) HZero where hSub _ _ = hZero instance (HSub a b c) = HSub (HSucc a) (HSucc b) c where hSub _ _ = hSub (undefined::a) (undefined::b) data Mult mult :: Mult mult = undefined instance (HList s,HMult a b c) = Apply Mult (HCons a (HCons
Re: [Haskell-cafe] tuples and Show in GHC
Remi Turk wrote: On Mon, Mar 07, 2005 at 12:05:41AM +, Keean Schupke wrote: Daniel Fischer wrote: The Show instances for tuples aren't automatically derived, they are defined in GHC.Show. So somewhere there must be an end, probably the author(s) thought that larger tuples than quintuples aren't used often enough to bother. That's not a principled reason but a practical one, but it's good enough for me. If you need them frequently and don't want to define your own instances, complain. BTW, tuples are defined in Data.Tuple up to 62-tuples and Eq and Ord instances are derived up to 15-tuples. In Hugs, apparently they are only provided up to quintuples. Has there been any work done on declaring instances over all tuples? It seems the pattern occurs fairly often, and is quite simple to abstract. Keean. Which almost sounds like a hint to replace the current tuples by HLists in Haskell 2? ;) Something like: infixr 5 :*: data HNil = HNil data HList b = a :*: b = a :*: !b deriving (Eq, Ord) -- type () = HNil type (a,b) = a :*: b :*: HNil type (a,b,c) = a :*: b :*: c :*: HNil fst :: HList b = (a :*: b) - a fst (a:*:b) = a Where (x,y,z) is syntactic sugar for x :*: y :*: z :*: HNil in much the same way [x,y,z] is syntactic sugar for x:y:z:[]... It might even be (almost?) backward compatible AFAICS. Groeten, Remi Whilst thats certainly one way to do it, HLists are composed of binary products (,)... So this works as long as you can imagine: (a,(b,(c,HNil))) == (a,b,c) We can define the operations generically using HLists, and we can even convert back and forth from a tuple to an HList (for a limited number of tuple instances). Infact we might be able to do conversion of arbitrary tuples using template-haskell. Keean. ___ 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)
Daniel Fischer wrote: And, BTW, that's why Keean et al's HList library doesn't help here either, the type of an HList determines the number of elements and the type of each, so there we face the same problems as with nested tuples. What we need is type Stack = [ArbitraryType] (from the HList paper, I surmise that [Dynamic] would be possilble, but that seems to have it's own problems). Well it depends on what you want to do... If the types of elements are determined by the computation then you can use an HList as is, and there is no problem. The only time there is a problem is if the _type_ of an element to be put in an HList depends on an IO action. In this case you need to existentially quanify the HList. So you can use the HList in both cases, but you have to deal with existential types if the type of the HList is dependant on IO (you dont have to do this if only the value of an element depends on IO). Keean. ___ 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)
Daniel Fischer wrote: I don't know Joy, but probably there the stack is (roughly) a heterogenous list, which is hard to model in Haskell, think of data Element = Bool Bool | Char Char | Int Int . . . | IntToBool (Int - Bool) . . . type Stack = [Element] and how to define functions for that, urgh. Not saying it isn't tricky - but thats what the HList library (http://www.cwi.nl/~ralf/HList) implements, a heterogenous list. It works slightly differently using classes, but does abstract the workings enough to be useful, to construct an HList you can do: hlist = a .*. (3:Int) .*. False .*. 'v' .*. HNil And provides head/tail functions and other useful list and set operators. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] tuples and Show in GHC
Daniel Fischer wrote: The Show instances for tuples aren't automatically derived, they are defined in GHC.Show. So somewhere there must be an end, probably the author(s) thought that larger tuples than quintuples aren't used often enough to bother. That's not a principled reason but a practical one, but it's good enough for me. If you need them frequently and don't want to define your own instances, complain. BTW, tuples are defined in Data.Tuple up to 62-tuples and Eq and Ord instances are derived up to 15-tuples. In Hugs, apparently they are only provided up to quintuples. Has there been any work done on declaring instances over all tuples? It seems the pattern occurs fairly often, and is quite simple to abstract. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] how do I avoid excessive constructor application?
Something like: class Coerce a b where coerce :: a - b The class must be in a separate file from the instance so that the compiler does not determine that a == b for all instances. instance Coerce a a where coerce = id If it turns out the left and right types do not match, you get a no instance of coerce for ... error. Keean. S. Alexander Jacobson wrote: I'd like to do this sort of thing with types other than Either. Is there a generic safe coerce function? -Alex- On Wed, 2 Mar 2005, Stefan Holdermans wrote: Lemmih, And you can fix it with some unsafeCoerce# magic. (: Actually, as I pointed out, the required coercion in perfectly safe, though not implicit: coerceRight :: Either a b - Either c b coerceRight (Right b) = Right b Regards, Stefan __ 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
Re: [Haskell-cafe] Re: New to haskell: unresolved overloading question
There are problems with this approach... Instance heads are only chosen by the pattern not the constraints, so: instance (Ord a, Num a) = ApproxEq a where x ~= y = (abs (x-y) 1) Will match any type at all (whether a member of Ord or Num or not) and then will fail if the particular type is not an instance of Ord or Num. Using incoherent-instances is almost certainly broken as it just stops the compiler complaining is a generic instance (like above) overlaps with a specific instance in the wrong way. Using the flag just makes GHC silently choose the _most_generic_instance_. Almost alwaysApproxEq we want the opposite behaviour and want GHC to choose the most specific instance in the case of overlap. However it should do what you want with just -foverlapping-instances -fundecidable-instances. Keean. Christian Maeder wrote Blair Fraser wrote: I'm new to haskell and I'm working through the class section of the gentle tutorial. I decided to implement an ApproxEq class (just for fun), but have run into problems. The code below works fine for units and bools, but gives an unresolved overloading error for Floats and Doubles. What's going on here? What does the error message mean and what did I do wrong? (I'm in Hugs.) -- ApproxEq: My first class. class (Eq a) = ApproxEq a where (~=) :: a - a - Bool x ~= y = x == y -- By default, check equality -- These two override default with same, just checking if it works instance ApproxEq () where () ~= () = Trueinstance ApproxEq Bool where x ~= y = x == y -- These two override default with different -- consider floating points equal if they differ by one or less instance ApproxEq Float where x ~= y = (abs (x-y) = 1) instance ApproxEq Double where x ~= y = (abs (x-y) = 1) More elegant seems to be: instance (Ord a, Num a) = ApproxEq a where x ~= y = (abs (x-y) 1) However, this requires extensions to Allow unsafe overlapping instances: hugs -98 +O ghci -fglasgow-exts -fallow-overlapping-instances -fallow-undecidable-instances -fallow-incoherent-instances -- This one dosn't work either, but it just depends on the other two instance ApproxEq a = ApproxEq [a] where [] ~= [] = True (x:xs) ~= (y:ys) = x ~= y xs ~= ys _ ~= _ = False Thanks, Blair ___ 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] What is MonadPlus good for?
Technically this is a use of MonadError, not MonadPlus (see earlier discussion about how IO is _not_ an instance of MonadPlus). Keean. David Roundy wrote: On Sat, Feb 12, 2005 at 01:08:59PM -0500, Benjamin Pierce wrote: I have seen lots of examples that show how it's useful to make some type constructor into an instance of Monad. Where can I find examples showing why it's good to take the trouble to show that something is also a MonadPlus? (I know there are many examples of things that *are* MonadPluses; what I want to know is why this is interesting. :-) I've been working on a typeclass that derives from MonadPlus which will encapsulate certain kinds of IO. With MonadPlus, you can write monadic code with exceptions and everything that may not be executed in the IO monad. You just use fail to throw exceptions, and mplus to catch them. class MonadPlus m = ReadableDirectory m where mInCurrentDirectory :: FilePath - m a - m a mGetDirectoryContents :: m [FilePath] mReadFilePS :: FilePath - m PackedString mReadFilePSs :: FilePath - m [PackedString] mReadFilePSs f = linesPS `liftM` mReadFilePS f One instance of this class is IO, but I can also have instances for in-memory data structures (outside the IO monad) or (or example) for reading a tarball from disk--which would be a monad that acts within the IO monad. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] What is MonadPlus good for?
[EMAIL PROTECTED] wrote: G'day all. Quoting David Roundy [EMAIL PROTECTED]: It might be interesting to write a backtracking IO-like monad which obeyed m mzero === mzero. I imagine you could do it for something like an ACID database, if you define === as meaning has the same final result on the database, which of course would only be useful if the database had sufficient locking that it couldn't have been read between the original m and the later mzero. You should talk to the logic programming community about this some time. As Lee Naish has pointed out on many occasions, it would involve finding a way to insert the page back into the laser printer and lift the toner off. Not quite... remember the IO monad is a function which returns an IO program... as long as none of the IO program has been executed it is possible to 'edit' the program to remove parts... The problem only really occurs in interactive programs, where input forces partial evaluation of the function result... once the function has been evaluated up to the input the output so far cannot be retracted. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] File path programme
Ben Rudiak-Gould wrote: I'm tentatively opposed to (B), since I think that the only interesting difference between Win32 and Posix paths is in the set of starting points you can name. (The path separator isn't very interesting.) But maybe it does make sense to have separate starting-point ADTs for each operating system. Then of course there's the issue that Win32 edge labels are Unicode, while Posix edge labels are [Word8]. Hmm. Several assumptions here... We might want more platforms than windows/unix. The separator for these systems is different (\ for windows / for unix - who knows what other obscure systems may use). It seems to me a type class would allow the user to add definitions for their platform (IE it is extensible)... datatypes tend to be hard to extend as you have to find every use in the code and modify it. For code to be portable it has to use a diffenernt path parser depending on the platform, but the code must not be different... One way of doing this would be to use a class... data Windows data Unix type System = Unix class ParsePath a where parsePath' :: a - String - Path instance ParsePath Windows where parsePath' _ a = ... instance ParsePath Unix where parsePath' _ a = ... If all paths can be expressed in a single type, it seems different path parsers and printers are required. All the other functions could operate on the standard datatype. This still leaves the problem of determining what system you are compiling on... I guess I still don't see the problem with having: #ifdef Unix type System = Unix #endif #ifdef Windows type System = Windows #endif In some library somewhere... Infact its the only way I can see of selecting the correct instance at compile time... and using classes is the only way I can think of making the system easily extensible (even if we use a single datatype for all paths) Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] File path programme
I guess it's just that I'm more concerned with making possible what is currently impossible (according to the library standards)--that is, using FFI and IO on the same file--rather than just adding utility features that application developers could have written themselves. I suppose we don't need a class for this, all we need is a couple of functions to convert between FilePath and CString. Except paths are different on different platforms... for example: /a/b/../c/hello\ there/test and: A:\a\b\ notice how the backslash is used to 'escape' a space or meta-character on unix, but is the path separator for windows. If you want to write portable applications, then you dont want to hard code the platform type. So converting from the datatype to a string is not simple: string = pathToString ... one way of doing this is to have pathToString call a function to determine the system type and construct the string accordingly. The problem here is that it is not extensible by the user, the supported platforms are determined by the library. By using a class we can let the user define translations for new platforms... Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] File path programme
Jules Bean wrote: only it isn't. That's a property of a shell, the underlying OS allows spaces in file names with no need for an escaping mechanism. Okay, that was a mistake... but it does not change the point, that pathToString needs to work out what platform it is on, and doing it without typeclasses makes it not extensible. We need a way of allowing people to define new path printers (as members of a class)... whilst having the program determine which platform it is on, and choosing the correct instance (at compile time). Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: Visual Programming Languages
Hmm, can't resist commenting on this one! Bayley, Alistair wrote: This was odd... Some cherry-picked quotes from the manifesto: http://alarmingdevelopment.org/index.php?p=5 - Visual languages are not the solution: ... common idea is to replace AST structures with some form of graphical diagram. ... Agree, point and grunt is much slower than entering commands. Its like being stuck in a country where you don't speak the language - all you can do is point at things and grunt ('click') and hope they understand you. - Programming is not Mathematics Disagree strongly... Bad programming seems to have little to do with mathematics, good programming often has the elegance of a well thought out proof. Beauty in programming is like beauty in mathematics. - Change is natural: There has been much effort expended to remove the concept of mutable state from programming, to be replaced by immutable values as in mathematics. This is entirely misguided. ... Monads are a reductio ad absurdum. [ Heresy! :-) ] Change is natural, but that has nothing to do with mutable state. Parallelism will make mutable state less attractive, as will hardware/software co-design. Isolating changes within a verifiable sandbox (like the ST/State monads) reduces errors due to unforseen interactions. - Control flow considered harmful: ... The primary reason for this is to permit side-effects to be ordered by the programmer. ... [ This appears to contradict the criticism of monads. ] Agree - control flow causes the possible paths (or corner cases) in the program to increase exponentially. Program correctness verification becomes much harder with more possible-paths. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Daniel Fischer wrote: I think, 1. should be acceptable to everybody, and 2. as a principle too, only the question of which effects are relevant needs to be answered. It's plain that not all measurable effects are relevant. My inclination to ignore the side-effects stemmed from the (irrational) desire to have IO's MonadPlus instance justified, now I'm prepared to say yes, side-effects such as output do count, so the instance MonadPlus IO is erroneous, but may be maintained for practical reasons. I am sure monads in Haskell (and other functional languages like ML) are defined on types not values. Therefore it only matters that the types are correct and that the operator obeys the associative laws. I am reasonably sure the values whether returned or side-effects are irrelevent. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
I think I see, but if the objects are types, arn't the morphisms functions on types not values? Keean. Ashley Yakeley wrote: In article [EMAIL PROTECTED], Keean Schupke [EMAIL PROTECTED] wrote: I am sure monads in Haskell (and other functional languages like ML) are defined on types not values. The objects of the category are types. The morphisms on the category are functions. Two functions are the same if they match each value to the same value. For the Functor laws and the Monad laws, the values certainly do matter: if they didn't, they wouldn't correspond to the category theory notions of functor and monad because the morphisms would be wrong. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Jules Bean wrote: No. Well: they are functions 'on' types, but functions 'on' types map values to values. Analogy: In the category of sets and functions, the objects are sets and the morphisms are functions. The functions --- from sets to sets --- take objects in one set to objects in another set. Specifically: A monad T is a (endo)functor T : * - * where * is the category of types, together with a multiplication mu and a unit eta. So, * is the category of Types, and functions on type (which map values to values), and T is an endofunctor (mapping functions on type to functions on type). How does this affect the IO monad though? m = (\a - mzero) === mzero If we consider the state monad, surely the above makes no comment on what the final state should be, only the final value returned... Or is MonadPlus not definable on State monads? If it is then considering IO === ST RealWorld, would imply that the actions of the IO monad are not important as long as the final value returned is mzero? Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Jules Bean wrote: Well, mzero isn't a return value in the IO monad, it's an exception. But yes, I agree with you that the (plausible) laws I have seen for MonadPlus seem to say that mzero should ignore the actions. But this in practice is not how IO behaves. Jules I can see three possible solutions: 1) IO is not an instance of MonadPlus (but may still be an instance of MonadError) 2) Side effects are ignored (or state is ignored) and IO may be an instance of MonadPlus 3) bind (=) is redefined for IO. As the IO Monad is a function which resturns a computation, bindIO can be changed such that (a mzero === mzero). In other words if the RHS is mzero, the LHS is not included in the final result (and its actions would not get executed), however this must be inconsistent if we consider: f = getChar = (\a - if a == F then mzero else return a) In this case if the LHS returns F the LHS should not have been run... this contradicts itself, so this is a non option I guess. Acutally looking at GHC CVS libraries, there is not a definition for MonadPlus on the state or IO monads... Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Jules Bean wrote: It's in Control.Monad.Error. Not documented though. Jules Ahh, so it is: instance MonadPlus IO where mzero = ioError (userError mzero) m `mplus` n = m `catch` \_ - n So, the author of this obviously subscribed to the view that side-effects are not counted when considering function identity... Keean ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Ashley Yakeley wrote: If you remember your category theory, you'll recall that two morphisms are not necessarily the same just because they're between the same two objects. For instance, the objects may be sets, and the morphisms may be functions between sets: morphisms from A to B are the same only if they map each element in A to the same element in B. Yes, but I though the 'objects' in this case are endofunctors from a type to itself... the the morphisms operate on these endofunctors, the morphisms are unit and join such that joining 'unit' to the endofuntor retults in the endofunctor. But I think that as the endofunctor is from the type to itself, the value does not come into it. A - A `join` unit = A - A Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Jules Bean wrote: I've lost track of what you mean by 'this case' and indeed of what you mean by 'join' (did you mean mplus? the word join is normally used for the operation of type m (m a) - m a, which is not often used directly in haskell) However, even addressing your point about endofunctors: for two endofunctors to be equal, they must be equal on all objects and all morphisms, which effectively means they must be pointwise equal on all values. Jules I think the endofunctors are defined on the types, not the values though. So the object of the category is the endofunctor (Type - Type), and unit and join are the identity and binary associative operator on which a Monad is defined. return and bind are defined in terms of unit and join. So unit is the identity which when joined to the endofunctor (Type - Type) results in the same endofunctor... Therefor: (Type - Type) `join` unit = (Type - Type) Now as the type of the IO monad is IO a we end up with: (IO a - IO a) `join` unit = (IO a - IO a) This is true irrespective of any side effects IO may have, as the type is the same for the IO action no matter what side effects it generates. At least thats how I understand it... Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: File path programme
Marcin 'Qrczak' Kowalczyk wrote: These rules agree on foo, foo. and foo.tar.gz, yet disagree on foo.bar.; I don't know which is more natural. Filename extensions come from DOS 8.3 format. In these kind of names only one '.' is allowed. Unix does not have filename extensions, as '.' is just a normal filename character (with the exception of '.', '..', and filenames starting with a '.' which are hidden files). As far as I know unix utilities like gzip look for specific extensions like '.gz', so it would make more sense on a unix platform to just look for a filename ending '.gz'... this applies recursively so: fred.tar.gz Is a tarred gzip file, so first ending is '.gz' the next is '.tar'... So as far as unix is concerned: foo.bar. is just as it is... as would any other combination unless the extension matches that specifically used by your application... So the most sensible approach would be to have a list of known extensions which can be recursively applied to the filenames, and leave any other filenames alone. [.gz,.tar,.zip] ... In other words just splitting on a '.' seems the wrong operation. (Imagine gziping a file called a... you get agz, in other words simply an appended .gz) Keean ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Ashley Yakeley wrote: I disagree. Clearly (putStrLn Hello mzero) is not the same as mzero. Yes it is, side effects are quite clearly not counted. The value of (putStrLn Hello mzero) is mzero. In reference to the idea of splitting MonadPlus, what category would you be operating in, if you have a zero but no co-product operation? Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Just thinking about this, a monad is a Functor plus two natural-tranformations, Unit and Join. Is there an equivalent definition for MonadPlus... I am not sure I understand where MonadPlus comes from? Is it just a Functor and two different definitions of Unit and Join (from those chosen to be in the class Monad?) Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Ashley Yakeley wrote: I don't believe this represents a good understanding of IO actions as Haskell values. For instance, 'return ()' and 'putStrLn Hello' are the same type, but are clearly different actions and so are usually considered to be different values. That the latter prints out text might be better considered not so much a side effect as the actual action itself. You've introduced the concept of the value of an IO action, apparently as something separated from side effects. I don't believe you can properly define this. For instance, what is the value of getChar such that it doesn't involve side effects? Right, but we are dealing with the type system here. Remember Haskell monoids are functors on types, not on values ... (ie the base objects the 'category theory' is applied to are the types not the values)... Therefore we only consider the types when considering Monads. As such if you wished to consider the examples you gave distinct, the type system would need to distinguish side effects... this can be done with a linear-aliasing type system, but not Haskell's as far as I know... Maybe you could write such types: {putStrLn Hello; mzero} :: IO (PutStrLn Hello = ()) ??? But if we look at the type of the Functor: fmap :: (a - b) - m a - m b Where is the IO action? Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Jorge Adriano Aires wrote: On the list monad, I think of the mplus operation as the union two non-deterministic states. Mzero is the state that works as the identity (which is when you have no possible state at all). Okay... thats a definition of a monoid. What would happen if this was the definition? instance MonadPlus [] where mzero = [] mplus a b | a == [] = b | otherwise = a Isn't the above a monoid as well? a `mplus` [] = a [] `mplus` b = b Still looks like an identity to me Is there only on correct definition of a monad/monoid on lists - or does anything that satisfies the monad laws count? I got the impression you could define anthing you liked for mzero and mplus - providing the laws are upheld? Then, I'd say you're not thinking of monadic sums, but of catching errors, and the appropriate place for that is the class MonadError. I am thinking about how some monads are summed - like Maybe and the Parser monad. It seems there are two possibilities - either the definitions of MonadPlus for Maybe and Parser monads are in Error, or there can be two different acceptable definitions of MonadPlus on the List? Keean ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Aaron Denney wrote: You can, but the other one turns it into a copy of the Maybe Monad, so the current one is more useful. So what does this mean in terms of Ashley's question: But only some instances (such as []) satisfy this: (mplus a b) = c = mplus (a = c) (b = c) Other instances (IO, Maybe) satisfy this: mplus (return a) b = return a Does it mean that both fall within the acceptable definition of the monad laws for MonadPlus? 1. |mzero = f == mzero| 2. |m = (\x - mzero) == mzero| 3. |mzero `mplus` m == m| 4. |m `mplus` mzero == m| So I guess I must have missed the point because the distinction between say a monad on [] and Maybe for example seems to me to be irrelevant to MonadPlus. The distinction comes down to mplus being the same as skipError for Maybe and different for []. Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Ashley Yakeley wrote: I think it would be helpful if all these classes came with their laws prominently attached in their Haddock documentation or wherever. The trouble with MonadPlus is that the precise set of associated laws is either unspecified or not the most useful (I assume there's a paper on the class somewhere). I think everyone can agree on these: mplus mzero a = a mplus a mzero = a mplus (mplus a b) c = mplus a (mplus b c) I think it would be even better if the classes came with assertions that 'enforced the laws'... I think this requires dependant types though. mzero = a = mzero But what about this? a mzero = mzero Well it was in the list I saw... I we consider the familar arithmetic product a * b * 0 -- it is clear that an mzero anywhere in a sequence should result in mzero: a b mzero c d = mzero But that says nothing about the co-product... where mzero should be the identity IE: a `mplus` mzero = a mzero `mplus` a = a But I am not sure there are any requirements on commutivity or associativity on the co-product operation? It's satisfied by [] and Maybe, but not IO (for instance, when a is 'putStrLn Hello'), but IO has been declared an instance of MonadPlus. And then there are the two I gave: (mplus a b) = c = mplus (a = c) (b = c) This was not on the list I saw - guess it could either be an omission, or it has nothing to do with MonadPlus ... monads with identity and co-product? ...which is satisfied by [], but not Maybe or IO. mplus (return a) b = return a ...which is satisfied by Maybe and IO, but not [], although your alternative declaration would make [] satisfy this and not the previous one. But one could make up any arbitrary law that is satisfied by some definition of a Monad and not others. Presumably there has to be some sound category-theoretic reason for including the law? Keean ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Ashley Yakeley wrote: In article [EMAIL PROTECTED], S. Alexander Jacobson [EMAIL PROTECTED] wrote: I assume there is a standard name for this class/function: instance Foo [] where foo [] = mzero foo (x:_) = return x instance Foo (Maybe x) where foo Nothing = mzero foo Just x = return x Surely they are incomplete monad definitions (has a return but no bind)... I don't believe so. I had to write my own classes to do this sort of thing. This is also a good opporunity to point out an ambiguity in the standard MonadPlus class. All instances satisfy these: mplus mzero a = a mplus a mzero = a But only some instances (such as []) satisfy this: (mplus a b) = c = mplus (a = c) (b = c) Other instances (IO, Maybe) satisfy this: mplus (return a) b = return a I think mplus should be separated into two functions. This code shows the difference a bit more clearly: do b - mplus (return True) (return False) if b then mzero else return () For the first kind this is the same as return (), for the second kind it's the same as mzero. But isnt the point of Monad plus, that to have a 'zero' implies failure (a normal monad cannot fail) - and failure implies choice (a `mplus` b) is a if a succeeds or b if a fails and b succeeds,or mzero if both fail. if you look at your first identity: mplus mzero a = a mplus a mzero = a This fits the above description, but I don't see how the following can be true: (mplus a b) = c = mplus (a = c) (b = c) The LHS says (if a fails run b) then run c. The RHS says if (a then c) fails run (b then c) Finally, mplus (return a) b = return a Is obvious because return a is not mzero, so it is true for all Monads that can fail. Or have I missed the point? Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Re: what is inverse of mzero and return?
Ashley Yakeley wrote: In article [EMAIL PROTECTED], Keean Schupke [EMAIL PROTECTED] wrote: This fits the above description, but I don't see how the following can be true: (mplus a b) = c = mplus (a = c) (b = c) Try it (and my test code) with [], which is an instance of MonadPlus. mplus is defined as (++) for []. but what if (a = c) causes c to fail, and (b = c) lets c succeed. In this case the LHS will fail, whereas the RHS will succeed I think? Keean. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe