Re: [Haskell] string type class

2009-03-06 Thread David Menendez
On Fri, Mar 6, 2009 at 12:05 PM, Wolfgang Jeltsch
 wrote:
> Am Freitag, 6. März 2009 17:31 schrieben Sie:
>> What name would you suggest?
>
> If we wouldn’t have to care about compatibility, I would name the class String
> and drop the type alias String.
>
> It’s hard to come up with a good name since String is already taken. However,
> things like StringLike, Stringy, Chars etc. are probable still better than
> IsString since they describe the things (values of instances of that class)
> instead of stating a property of them.

How about CharSequence?

-- 
Dave Menendez 

___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] An Alternative Data.List.Zipper

2009-01-17 Thread David Menendez
On Sat, Jan 17, 2009 at 9:13 PM,   wrote:
> On Sat, 17 Jan 2009, David Menendez wrote:
>
>> instance Applicative f => Applicative (Backwards f) where
>>   pure = B . pure
>>   f <*> x = B (unB f <**> unB x)
>
> probably should be f <*> x = B (unB x <**> unB f)

I always get that backwards.

> anyhow, this should be part of Control.Applicative.

I agree. But until it is, we'll have to make do.

>> This may be terminological confusion. I would have said that a
>> PointedList *is* a zipper.
>
> This is what I thought, and what how I initally advised Jeff.  However after
> carefully reading both <http://en.wikibooks.org/wiki/Haskell/Zippers> and
> <http://www.cs.nott.ac.uk/~ctm/Dissect.pdf> (Clowns to the left of me,
> jokers to the right), it is clear that formally a zipper focuses on a
> sub-list / sub-tree rather than focusing on a particular node of a list or a
> tree.  Hence zippers are not comonads.

Funny, I was just reading that paper earlier today.

You're right. I wasn't making enough of a distinction between zippers
and structures with one selected element. It's the latter which are
comonads.

-- 
Dave Menendez 
<http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] An Alternative Data.List.Zipper

2009-01-17 Thread David Menendez
On Sat, Jan 17, 2009 at 7:49 PM, Jeff Wheeler  wrote:
> On Sat, 2009-01-17 at 17:41 -0500, David Menendez wrote:
>> That's correct, but I think you'd be better off defining OpApplicative
>> (or Backward, as I call it) locally and avoiding the two reverses.
>
> I'll have to look into this more; I don't really understand applicatives
> right now, so I can't use them yet. :)

newtype Backwards f a = B { unB :: f a }

instance Functor f => Functor (Backwards f) where
fmap f = B . fmap f . unB

instance Applicative f => Applicative (Backwards f) where
pure = B . pure
f <*> x = B (unB f <**> unB x)

traverseBackwards :: (Traversable t, Applicative f) = (a -> f b) -> t
a -> t (f b)
traverseBackwards f = unB . traverse (B . f)

>> If you look at a zipper as a list with a selected element, then it
>> doesn't make sense to talk about a zipper of an empty list.
>
> Apparently a zipper can be empty, as the focus is the rest of the list,
> not the current element. It seems that my file is not a Zipper, but
> rather a PointedList (thanks to roconner in #haskell).

This may be terminological confusion. I would have said that a
PointedList *is* a zipper.

Certainly, from the standpoint that zippers are comonads, you can't
have an empty zipper, because you always need to be able to retrieve
the selected value.

>> That being said, I'd prefer fromList to have the type [a] -> Maybe
>> (Zipper a), and similarly with next and previous. If people want to
>> live dangerously, they can use fromJust.
>
> I agree, and I've made this change. I found this annoying on
> next/previous though, so I've created a tryNext/tryPrevious that'll
> return an unchanged PointedList if it's already on the end.

I would define tryNext in terms of next, rather than the other way
around, but I guess it shouldn't make much difference. I'm also not
sure that returning the original pointed list is a good idea, since
trying to move beyond the boundaries of the zipper will usually be an
error.

-- 
Dave Menendez 
<http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] An Alternative Data.List.Zipper

2009-01-17 Thread David Menendez
On Sat, Jan 17, 2009 at 4:32 PM, Jeff Wheeler  wrote:
> On Sat, 2009-01-17 at 21:55 +0100, Jean-Philippe Bernardy wrote:
>
>> I think it should admit empty, and the traversable instance should
>> traverse the first list in reverse.
>
> I fixed the latter issue so that the behavior is correct (I think).

That's correct, but I think you'd be better off defining OpApplicative
(or Backward, as I call it) locally and avoiding the two reverses.

> I'm undecided about allowing them to be empty. I don't know the theory
> or math behind zippers (I'm sure there are some papers written about
> it), but it doesn't make much sense to be empty. I got that impression
> from #haskell, also.

If you look at a zipper as a list with a selected element, then it
doesn't make sense to talk about a zipper of an empty list.

That being said, I'd prefer fromList to have the type [a] -> Maybe
(Zipper a), and similarly with next and previous. If people want to
live dangerously, they can use fromJust.

-- 
Dave Menendez 

___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Passing typeclasses as parameters?

2008-03-14 Thread David Menendez
On Fri, Mar 14, 2008 at 8:06 AM, Ville Tirronen <[EMAIL PROTECTED]> wrote:
> Hi all.
>
>  I managed to paint myself in a corner where I did this:
>
>  > data ShowDynamic = forall a . (Show a) => SD Dynamic a
>  > toShowDyn a = SD (toDyn a) a
>  > fromShowDyn (SD d a) = fromDynamic d
>
>  > instance Show ShowDynamic where ...
>
>  Then I began to wonder if there was any hack to do:
>
>  > data AnyDynamic X = forall a . (X a) => AD Dynamic a
>
>  which could be kinda neat, but I saw no obvious way to do this.
>  Ideas?

You can't abstract over type classes, but you can abstract over a dictionary.

data ShowD a = ShowD { showD :: a -> String }

data AnyDynamic dict = forall a. AD Dynamic (dict a)

On the other hand, if all you need is some fixed intersection of
classes, it's better to make your own Dynamic.

data ShowableDynamic = forall a. (Show a, Typeable a) => SD a

toShowDyn :: (Show a, Typeable a) => a -> ShowableDynamic
toShowDyn = SD

fromShowDyn :: (Show a, Typeable a) => ShowableDynamic -> Maybe a
fromShowDyn (SD a) = cast a

Finally, you can make your own dynamic augmented with an arbitrary dictionary:

data AnyDynamic dict = forall a. (Typeable a) => AD a (dict a)

-- 
Dave Menendez <[EMAIL PROTECTED]>

___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] detecting existing instances

2008-01-09 Thread David Menendez
On Jan 9, 2008 3:10 PM, Ralf Laemmel <[EMAIL PROTECTED]> wrote:
>
> Type-level type cast is the type-level programmer's swiss army knife.


> See the illustration below.
>

Does this get any easier with type families? Your (TypeCast a b) seems
similar in intent to (a ~ b), but I'm not familiar enough with the latter to
know whether it would work here.

-- 
Dave Menendez <[EMAIL PROTECTED]>

___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Haskell Applications - reg

2007-10-04 Thread David Menendez
On 10/4/07, Ganesh Narayan <[EMAIL PROTECTED]> wrote:
> True,  but I was of the opinion that -O0, -fno-state-hack and
> -fno-full-laziness would preserve the calling structure with minimal
> perturbance. Wouldn't it? Besides, I am hardly aware of any utility that
> generates source level call graph/expression dependence graph; suppose one
> can generate a module dependency graph, but guess its little too coarse!

You might have more luck with JHC, which (if I understand correctly)
creates intermediate C code that somewhat resembles the Haskell source
in structure.

-- 
Dave Menendez <[EMAIL PROTECTED]>

___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] ST vs State

2007-05-30 Thread David Menendez
David Menendez writes:

> It's also possible to write ST in terms of State. 
> 
> Assume we have a Store ADT with this interface:
> 
> data Store r
> data STRef r a
> withStore :: (forall r. Store r -> a) -> a
> newRef:: a -> Store r -> (STRef r a, Store r)
> readRef   :: STRef r a -> Store r -> a
> writeRef  :: STRef r a -> a -> Store r -> Store r
> 
> (The 'r' parameter is to make sure that references are only used with
> the Store that created them. The signature of withStore effectively
> gives every Store a unique value for r.)

Rats. The rank-2 type isn't enough to guarantee type-safety. You need a
monad (or linear types) to make sure that the Store is used
single-threadedly.

Using the API above, you can defeat the type checker.

coerce :: a -> b
coerce a = withStore (\s0 -> 
let (r1,s1) = newRef a s0
(r2,s2) = newRef undefined s0
in readRef r2 s1)

(Of course, you would have needed a function like coerce to implement
the API in the first place.)
-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] ST vs State

2007-05-30 Thread David Menendez
Federico Squartini writes:

> Hello dear Haskellers,
> 
> Could someone be kind and explain with some detail what are the
> differences between the two monads:
> 
> Control.Monad.ST
> And
> Control.Monad.State
> ?
> 
> They are both meant to model stateful computation but they are not the
> same monad. The first one represents state with in place update?

Conceptually, the difference is in the API. State can be thought of as
an ST with a single, implicit reference cell. Alternately, ST can be
thought of as a State which manipulates a store of values.


Here's a simple implementation of State using ST:

newtype State s a = State 
{ unState :: forall r. ReaderT (STRef r s) (ST r) a }

runState :: State s a -> s -> (a,s)
runState m s0 = runST (do
r <- newSTRef s0
a <- runReaderT (unState m) r
s <- readSTRef r
return (a,s))

instance Monad (State s) where
return a = State (return a)
m >>= f  = State (unState m >>= unState . f)

instance MonadState s (State s) where
get   = State (ask >>= lift . readSTRef)
put x = State (ask >>= \s -> lift (writeSTRef s x))


It's also possible to write ST in terms of State. 

Assume we have a Store ADT with this interface:

data Store r
data STRef r a
withStore :: (forall r. Store r -> a) -> a
newRef:: a -> Store r -> (STRef r a, Store r)
readRef   :: STRef r a -> Store r -> a
writeRef  :: STRef r a -> a -> Store r -> Store r

(The 'r' parameter is to make sure that references are only used with
the Store that created them. The signature of withStore effectively
gives every Store a unique value for r.)

Then we can define ST like so:

newtype ST r a = ST { unST :: State (Store r) a } deriving Monad

runST :: (forall r. ST r a) -> a
runST m = withStore (evalState (unST m))

newSTRef :: a -> ST r (STRef r a)
newSTRef a = ST $ do 
s <- get
let (r,s') = newRef a s
put s'
return r

readSTRef :: STRef r a -> ST r a
readSTRef r = ST $ gets (readRef r)

writeSTRef :: STRef r a -> a -> ST r ()
writeSTRef r a = ST $ modify (writeRef r a)

There are two subtleties. The first is that you can't implement Store
without cheating at some level (e.g., unsafeCoerce). The second is that
the real ST implementation uses in-place update, which is only safe
because the Store is implicit and used single-threadedly.
-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] ANNOUNCE: Data.CompactString 0.1 - my attempt at a Unicode ByteString

2007-02-05 Thread David Menendez
Alistair Bayley writes:

> On 05/02/07, Chris Kuklewicz <[EMAIL PROTECTED]> wrote:

> > UTF-8 is a 4 byte encoding.  There is no valid UTF-8 5 or 6 byte
> > encoding.
> 
> Chris is right here, in that Takusen's decoder is incorrect w.r.t. the
> standard, in allowing up to 6 bytes to encode a single char.

 

> There's nothing stopping the Unicode consortium from expanding the
> range of codepoints, is there? Or have they said that'll never happen?

I believe they have. In particular, UTF-16 only supports code points up
to 10.

From <http://en.wikipedia.org/wiki/Universal_Character_Set>:

> the UCS stops at 10 and ISO/IEC 10646 has stated that all future
> assignments of characters will also take place in that range
[...]
> ISO 10646 was limited to contain as many characters as could be
> encoded by UTF-16 and no more, that is, a little over a million
> characters instead of over 2,000 million
-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Long live Edison

2006-02-20 Thread David Menendez
[EMAIL PROTECTED] writes:

> G'day all.
> 
> Quoting Robert Dockins <[EMAIL PROTECTED]>:
> 
> > -- The Sequence 'rcons' method takes its arguments in the opposite
> > order as the 'lcons' method (for mnemonic purposes).  Should the
> > arguments to 'rcons' be reversed?
> 
> The argument is that they both take their arguments in the order
> that they would do were they implemented with concatenation:
> 
> lcons x xs === [x] ++ xs
> rcons xs x === xs ++ [x]
> 
> This certainly makes sense to me.  Is there an argument for using
> the other order?

The order of rcons is also natural for using in-line, e.g. "xs `rcons`
x".
-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] generic catch in a MonadIO

2006-02-07 Thread David Menendez
[EMAIL PROTECTED] writes:

> The implementation is quite trivial.
> 
> > class MonadIO m => CaughtMonadIO m where
> > gcatch :: m a -> (Exception -> m a) -> m a
> >
> > instance CaughtMonadIO IO where
> > gcatch = Control.Exception.catch
> 
> > instance (CaughtMonadIO m, Error e) => CaughtMonadIO (ErrorT e m)
where
> > gcatch m f = mapErrorT (\m -> gcatch m (\e -> runErrorT $ f e))
m

Since the monad transformers in MTL all promote MonadError, you can also
use throwError and catchError with instances of MonadIO. Currently, the
error type associated with IO is IOError, not Exception, but it should
be possible to work around that with a wrapper:

newtype IO' a = IO' { unIO' :: IO a } deriving (Monad, Functor)

instance MonadIO IO' where
liftIO = IO'

instance MonadError Exception IO' where
    throwError = IO' . throwIO
m `catchError` h = IO' $ catch (unIO' m) (unIO' . h)
-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Re: haskell.org Public Domain

2006-01-10 Thread David Menendez
Wolfgang Jeltsch writes:

> Maybe we should start with forcing everything on the wiki to be
> licensed under a permissive license.  We could use the one Udo
> proposed.  Or we could use a BSD-style license so that we can
> incorporate parts of already existing BSD-style-licensed material.
> BSD is also rather permissive.

How well would BSD work with wiki content? If I see a useful bit of code
on the wiki and I want to use it, BSD requires me to acknowledge the
author's copyright, but who is the author?

As a concrete example, the old wiki has an implementation of Ralf
Hinze's nondeterminism monad. If I use that in a project, do I need to
credit Ralf? The person who typed it into the wiki? Anyone who modified
it? The wiki itself?

How much code do you need to borrow from the wiki before you need to
provide an acknowledgement?
-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] A collection of related proposals regarding monads

2006-01-04 Thread David Menendez
Cale Gibbard writes:

> I personally feel that the inclusion of 'fail' in the Monad class is
> an ugly solution to the problem of pattern matching, and gives the
> incorrect impression that monads should have some builtin notion of
> failure. Indeed, it's becoming common to type the result of some
> function in an arbitrary monad in order to indicate the potential for
> failure, which is strictly speaking, not the right thing to do. (In a
> lot of cases, it's going to be no better than complete program
> failure)
> 
> We ought to be using MonadZero when we want to express failure, but
> it's gone!

Yeah, I don't like fail either. In fact, I usually forget to define it,
even for instances of MonadPlus.

There are typically three ways to indicate error in existing monad
libraries, e.g.,

mzero  :: MonadPlus m =>  m a
fail   :: Monad m =>String -> m a
throwError :: MonadError e m =>  e -> m a
 
I would say that fail and throwError essentially have the same meaning,
but I distinguish them from mzero. To my mind, 'mzero' means "no
answer", whereas fail and throwError mean "something's wrong".

For example, my implementation of Nondet doesn't backtrack over errors:

mzero`mplus` m = m
throwError e `mplus` m = throwError e

Should a pattern match failure call mzero or throwError? I was
originally going to say throwError, but now I'm not so sure. First,
MonadError is severely non-H98 (fundeps). Second, we would either need
the error type to belong to some class which includes pattern match
failures, or have a dedicated throwPatternMatchFailure method in
MonadError. Finally, you can write sensible code which backtracks on
pattern-match failure, e.g.,

do ...
   Just a <- lookup ...
   ...

> Even if this translation of do-syntax isn't accepted, I still think
> that we should have a separate MonadZero.

I like the idea of a separate MonadZero. Do we know why it was combined
with MonadPlus? Were there efficiency concerns, or did people dislike
having to declare all those separate instances?

> I'd also like to see the current use of MonadPlus split into MonadElse
> (or MonadOr) and MonadPlus, as described at the bottom of
> http://www.haskell.org/hawiki/MonadPlus
> as it helps to clarify the distinction between backtracking-type
> failure and immediate failure in types. We could even put this
> distinction to good use in many monads which do support backtracking
> anyway:
> 
> instance MonadElse [] where
> [] `morelse` ys = ys
> (x:xs) `morelse` ys = (x:xs)

With backtracking monads, you can use Oleg's msplit operator to get
morelse, soft-cut, and various other operations.

class MonadPlus m => MonadChoice m where
msplit :: m a -> m (Maybe (a, m a))

mif :: MonadSplit m => m a -> (a -> m b) -> m b -> m b
mif p t e = msplit p >>= maybe e (\(x,xs) -> t x `mplus` (xs >>= t))

a `orElse` b = mif a return b

With non-backtracking monads, you can use throwError or just use mplus
and remind people that non-backtracking monads don't backtrack.

> Lastly, it would be nice to have some standard name for the function:
> option :: (MonadPlus m) => [a] -> m a
> option = foldr (mplus . return) mzero
> which seems to come up quite a bit in my experience with nondet
> monads.

Mine too. Someone else mentioned "choose", which seems nice. Or,
"fromList".

Incidentally, would GHC optimize "msum (map return xs)" to "foldr (mplus
. return) mzero xs"?

> P.S. Oh, and don't get me started about the whole Functor subclass
> thing, and the inclusion of join in the Monad class. Of course I want
> those too. :)

For the recond, my ideal hierarchy would look something like this:

class Functor f where
map :: (a -> b) -> f a -> f b

class Functor f => Applicative f where
return :: a -> f a
ap :: f (a -> b) -> f a -> f b
lift2  :: (a -> b -> c) -> f a -> f b -> f c

ap = lift2 ($)
lift2 f a b = map f a `ap` b

class Applicative m => Monad m where
join  :: m (m a) -> m a
(>>=) :: m a -> (a -> m b) -> m b

join m = m >>= id
m >>= f = join (map f m)

class Monad m => MonadZero m where
nothing :: m a
    
class MonadZero m => MonadPlus m where
(++) :: m a -> m a -> m a

class MonadPlus m => MonadChoice m where
msplit :: m a -> m (Maybe (a, m a))

I guess you could put "return" in its own class, PointedFunctor, between
Functor and Applicative, but I haven't seen a reason to. Even without
that, it's probably excessive.

-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] GADT type inference problem

2005-11-30 Thread David Menendez
[EMAIL PROTECTED] writes:

> 
> Let us consider the following simple code
> 
> > {-# OPTIONS -fglasgow-exts #-}
> >
> > module Foo where
> >
> > data Term a where
> >B:: Bool -> Term Bool
> >C:: Term Bool -> Term t -> Term t 
> >I:: Int -> Term Int
> >
> > shw (I t) = ("I "++) . shows t
> > shw (B t) = ("B "++) . shows t
> > shw (C p q) = ("Cnd "++) . (shw p) . (shw q)
...
> 
> However, when we do
> 
>   *Foo> :t shw
>   shw :: Term Bool -> String -> [Char]
> 
> The inferred type of shw shows that it takes the values of 
> Term *Bool*. 

As I understand it, GHC can't infer the most general type signature when
GADTs are involved. It should work if shw has an explicit type
signature, e.g. shw :: Term a -> ShowS

What's strange is that GHC accepted the code at all. There would
probably be less confusion if GADT arguments always required a
signature, like arguments involving higher-rank polymorphism.
-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] really undecidable instances?

2005-10-30 Thread David Menendez
Benjamin Franksen writes:

> This is the data type declaration:
> 
> > data Node23 tree a
> >   = N2 (tree a) a (tree a)
> >   | N3 (tree a) a (tree a) a (tree a)
> 
> and this is the instance, where the error is reported:
> 
> > instance (Pretty a, Pretty (tree a)) => Pretty (Node23 tree a) where
> >   ...
> 
> The class Pretty is from Daan Leijen's pprint library.
> 
> I think that the 'non-type variable' refered to above is the
> application (tree a) in the constraint (Pretty (tree a)), which is
> arguably "almost" a type variable. In this case I think it is even
> more obvious that it can't cause a loop, since the LHS clearly has a
> type constructor removed, right?
> 
> I mention this mainly because my module is otherwise completely H98
> and I thought it would be nice to keep it that way. I need the Pretty
> instance for debugging only, so it's not really a show-stopper. Still
> I wonder if somebody knows a work-around that doesn't need a language
> extension (some newtype trick, maybe?).

I believe the "correct" way to do this is with a Pretty-promoting
constructor class.


class Pretty'1 f where
pretty'1 :: Pretty a => f a -> Doc
prettyList'1 :: Pretty a => [f a] -> Doc

instance (Pretty a, Pretty'1 tree) => Pretty (Node23 tree a) where
...

Your typical Pretty'1 instance will look like this:

instance Pretty'1 T where
pretty'1 = pretty
prettyList'1 = prettyList

-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] PROPOSAL: class aliases

2005-10-13 Thread David Menendez
Udo Stenzel writes:

> Simon Peyton-Jones wrote:
> > I've considered this before, but never done anything about it
> > because superclasses are so close.  Specifically, what is the
> > difference between
> > 
> > (i) class (C a, D a) => CD a
> > and
> > (ii)class alias CD a = (C a, D a)
> > 
> > Note that (i) is Haskell 98.
> 
> I was about to suggest almost exactly the same.  In particular, John's
> proposal could be decomposed into three parts:
> 
> 1. Allow instance declarations to define methods of superclasses.
>These are simply converted into the appropriate instance 
>declarations for the superclasses.
> 
> 2. Allow class declarations to give defaults for methods in
>superclasses.  Together with (1) they are used in the obvious way.
> 
> 3. Allow empty instance declarations to be implicitly generated.
> 
> 
> As a nice side effect, (1) and (2) together would allow us to cleanly
> get rid of the fmap/liftM annoyance:
> 
> *> class Functor f where { fmap :: ... }
> *> class Functor m => Monad m where { fmap = liftM }

This can also get us into trouble. Consider,

class Functor f where fmap :: ...
class Functor m => Monad m where { fmap = liftM; ... }
class Functor d => Comonad d where { fmap = liftD; ... }

The Id functor is an instance of Monad and Comonad; what happens to the
fmap definition?

> If the instance for every type were allowed, Foo and Bar would be
> indistinguishable from true synonyms.  Further, if classes with no
> methods have no use currently, this "universal instance" could be
> compiler generated whenever a class without methods is declared.  Or 
> the empty class may be treated as a synonym, if that's simpler.  Does 
> this make any sense?

I don't know that method-less classes have *no* value. You could use
them to make additional claims about a type. For example,

class Monoid m where { ... }

class CommutativeMonoid m where {}

The idea being that instances of CommutativeMonoid satisfy additional
laws.
-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] getArgs, maxBound, float division: pure functions?

2005-10-11 Thread David Menendez
[EMAIL PROTECTED] writes:

> Regarding argument 1: the value of |maxBound :: Int| is also the
> function of the environment. Haskell98 Report says [p82, Section
> 6.4]
> 
>The finite-precision integer type Int covers at least the range 
>[ - 2^29 , 2^29 - 1 ]. As Int is an instance of the Bounded class, 
>maxBound and minBound can be used to determine the exact Int range
>defined by an implementation.
> 
> Thus, the value of |maxBound :: Int| may conceivably change from on
> program run (under runhugs32 on an AMD64 platform) to another (under
> runghc64 on the same platform).

I guess we could declare 32- and 64-bit Ints to be distinct types, and
then do a system call to get the native Int type.

data SomeIntegral = forall a. Integral a => SomeIntegral a

nativeInt :: IO SomeIntegral

main = case nativeInt of
SomeIntegral (_::int) -> print (maxBound :: int)

The disadvantage would be the need for polymorphism over the Integral
class whenever we wanted native-sized integers.

> Regarding argument 2: the existence of System.Environment.withArgs
> seems to doom getArgs to remain with the IO type. It cannot be a pure
> function. The simple extension of the argument points however to
> inconsistency with the floating-point facility. Haskell98 Report
> permits an implementation to use IEEE FP for Haskell Floats and
> Doubles. The Report specifically provides the class RealFrac to give a
> program access to some aspects of the IEEE FP system. IEEE FP
> computations are sensitive to the rounding mode, which is observable
> in pure code. The rounding mode can be changed. [...] Should all 
> floating-point computations be put in the IO monad?

In principle, you could use seperate types to distinguish floats with
different rounding modes, but I imagine this would be difficult or
annoying to implement.
-- 
David Menendez <[EMAIL PROTECTED]> <http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Paper: The essence of dataflow programming

2005-09-25 Thread David Menendez
n Fibonacci
numbers, then they are O(n^2). This is because each calculation occurs
separately. Consider the signature of sum:

sum :: Num a => History a -> a

The use of fby makes it seem like sum is using past calculations, but in
fact there can be no communication from one invocation of sum to the
next. Thus, sum is O(n), but "coextend sum" is O(n^2).


There are other arrows with better performance. Consider the automaton
arrow[3]:

newtype Auto a b = Auto (a -> (b, Auto a b))

This is an instance of Arrow, ArrowChoice, and ArrowLoop. It supports a
delay operation, just like the History comonad and its relatives. Its
versions of posA, sumA, and fiboA are O(n). To gain that performance, it
gives up power: Auto is not an instance of ArrowApply, meaning iniA has
to be defined as a primitive.


I don't have any conclusion, except to say that it's great to see some
examples of comonads in action. I had heard comonads described as
encapsulating context-dependence, much as monads encapsulate effects,
but I never had a good sense of what that meant before now.

Actually, the context-dependence angle also suggests a connection to
zippers[4]. I guess that's my next project.


[1] <http://citeseer.ist.psu.edu/kieburtz99codata.html>
[2] <http://haskell.org/yampa/>
[3] <http://haskell.org/arrows/arrows/Control.Arrow.Transformer.
Automaton.html>
[4] <http://haskell.org/hawiki/TheZipper>
-- 
David Menendez <[EMAIL PROTECTED]> <http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


[Haskell] Fixed-length vectors in Haskell, Part 2: Using no extensions

2005-05-07 Thread David Menendez
= const Nil
>
> instance (Num a, Vec v) => Num (Vec_s v a) where
> (+) = vzipWith (+)
> (*) = vzipWith (*)
> (-) = vzipWith (-)
> negate  = fmap negate
> abs = fmap abs
> signum  = fmap signum
> fromInteger = vec . fromInteger
>
> --
> newtype Diag a v = Diag { runDiag :: v (v a) -> v a }
>
> diag :: Vec v => v (v a) -> v a
> diag = runDiag vecCase
>
> instance VecCase (Diag a) where
> caseNil  = Diag (\_ -> Nil)
> caseCons = Diag (\(Cons x xs) ->
>Cons (vhead x) (diag (fmap vtail xs)))
> --
>
> instance Monad Vec_0 where
> return _ = Nil
> m >>= k  = Nil
>
> instance Vec v => Monad (Vec_s v) where
> return  = vec
> m >>= k = diag (fmap k m)

We can't declare a type synonym for matrices, because vector lengths are
no longer a separate part of the type signature, but we can still define
matrix functions.

> mat :: (Vec v, Vec w) => a -> v (w a)
> mat x = vec (vec x)
>
> fromLists :: (Vec v, Vec w) => [[a]] -> Maybe (v (w a))
> fromLists xs = mapM fromList xs >>= fromList
>
> row :: v a -> Vec_1 (v a)
> row v = Cons v Nil
>
> col :: Vec v => v a -> v (Vec_1 a)
> col = fmap (\v -> Cons v Nil)
>
> --
> newtype Transpose a w v = Transpose
> { runTranspose :: v (w a) -> w (v a) }
>
> transpose :: (Vec v, Vec w) => v (w a) -> w (v a)
> transpose = runTranspose vecCase
> 
> instance Vec w => VecCase (Transpose a w) where
> caseNil  = Transpose (\Nil -> vec Nil)
> caseCons = Transpose (\(Cons x xs) ->
>vzipWith Cons x (transpose xs))
> --
>
> mult :: (Vec v, Vec t, Vec w, Num a) => v (t a) -> t (w a) -> v (w a)
> mult x y = fmap (\r -> fmap (inner r) y') x
> where y' = transpose y
>
> --
> newtype IdMat a v = IdMat { runIdMat :: v (v a) }
>
> idMat :: (Vec v, Num a) => v (v a)
> idMat = runIdMat vecCase
>
> instance Num a => VecCase (IdMat a) where
> caseNil  = IdMat Nil
> caseCons = IdMat (Cons (Cons 1 (vec 0)) (fmap (Cons 0) idMat))
> --
-- 
David Menendez <[EMAIL PROTECTED]> <http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


[Haskell] Fixed-length vectors in Haskell, Part 1: Using GADTs

2005-05-07 Thread David Menendez
ple, here is the code for vec:

> newtype MkVec a n = MkVec { runMkVec :: a -> Vec n a }
>
> vec :: Nat n => a -> Vec n a
> vec = runMkVec natCase
>
> instance NatCase (MkVec a) where
> caseZero = MkVec (\x -> Nil)
> caseSucc = MkVec (\x -> Cons x (vec x))

Here's another function, which converts a list to a vector, provided
the list is long enough:

> newtype FromList a n = FromList
> { runFromList :: [a] -> Maybe (Vec n a) }
>
> fromList :: Nat n => [a] -> Maybe (Vec n a)
> fromList = runFromList natCase
>
> instance NatCase (FromList a) where
> caseZero = FromList (\l -> Just Nil)
> caseSucc = FromList (\l -> case l of
>x:xs -> fmap (Cons x) (fromList xs)
>[]   -> Nothing
>)

WIth this technique we can create as many functions which have
type-specific behavior for naturals as we need, without having to create
new classes or member functions.

With vec, we can make Vec n an instance of Sequence, from the Arrow
Transformer Library:

*> instance Nat n => Sequence (Vec n) where
*> lift0 = vec
*> lift2 = vzipWith

In fact, we can go further and make Vec n a monad. Since we already have
fmap, we just need an equivalent to join; that is, a function that takes
a vector of vectors, and returns a vector. One possibility is to take
the nth element of the nth vector, like so:

> diag :: Vec n (Vec n a) -> Vec n a
> diag Nil = Nil
> diag (Cons x xs) = Cons (vhead x) (diag (fmap vtail xs))
>
> instance Nat n => Monad (Vec n) where
> return  = vec
> m >>= k = diag (fmap k m)

This might make the Sequence instance seem superfluous, since 'lift0'
and 'lift2' correspond to 'return' and 'liftM2', respectively, but
'lift2' is able to take advantage of the vector's structure in a way
that 'liftM2' cannot. Thus, lift2 is O(n), whereas liftM2 has three
calls to diag, which is O(n^2). ('fmap' is better than 'liftM' for
similar reasons.)


More interestingly, we can make Vec n a an instance of Num:

> instance Show a => Show (Vec n a) where show = show . toList
> 
> instance Eq a => Eq (Vec n a) where
> Nil   == Nil   = True
> Cons x xs == Cons y ys = x == y && xs == ys
>
> -- alternately, x == y = vfoldr (&&) True (vzipWith (==) x y)
>
> instance (Nat n, Num a) => Num (Vec n a) where
> (+) = vzipWith (+)
> (*) = vzipWith (*)
> (-) = vzipWith (-)
> negate  = fmap negate
> abs = fmap abs
> signum  = fmap signum
> fromInteger = vec . fromInteger

This gives us element-wise arithmetic on equal-sized vectors and
scalar arithmetic.

*Vector_GADT> let v = Cons 1 (Cons 2 (Cons 3 (Cons 4 Nil)))
*Vector_GADT> v
[1,2,3,4]
*Vector_GADT> 3 + v
[4,5,6,7]
*Vector_GADT> 3 * v
[3,6,9,12]
*Vector_GADT> v + v
[2,4,6,8]
*Vector_GADT> v * v
[1,4,9,16]


Using fixed-length vectors, we can create matrices which are guaranteed
to be rectangular.

> type Matrix m n a = Vec m (Vec n a)
>
> mat :: (Nat m, Nat n) => a -> Matrix m n a
> mat x = vec (vec x)
>
> fromLists :: (Nat m, Nat n) => [[a]] -> Maybe (Matrix m n a)
> fromLists xs = mapM fromList xs >>= fromList
>
> row :: Vec n a -> Matrix One n a
> row v = Cons v Nil
>
> col :: Vec n a -> Matrix n One a
> col = fmap (\x -> Cons x Nil)

Because matrices are just vectors of vectors, the old instances for
Eq, Show, and Num still apply.

*Vector_GADT>
let Just (m::Matrix Two Two Int) = fromLists [[1,2],[3,4]]
*Vector_GADT> m
[[1,2],[3,4]]
*Vector_GADT> m + 1
[[2,3],[4,5]]
*Vector_GADT> m * m + m == m * (m + 1)
True

We can define functions to transpose and multiply matrices that
guarantee the dimensions will work out.

> transpose :: Nat n => Matrix m n a -> Matrix n m a
> transpose Nil = vec Nil
> transpose (Cons x xs) = vzipWith Cons x (transpose xs)
>
> mult :: (Nat n, Num a) => Matrix k m a -> Matrix m n a -> Matrix k n a
> mult x y = fmap (\r -> fmap (inner r) y') x
> where y' = transpose y

*Vector_GADT> row v `mult` col v
[[30]]
*Vector_GADT> col v `mult` row v
[[1,2,3,4],[2,4,6,8],[3,6,9,12],[4,8,12,16]]

We can even define a zero-argument function that creates an identity
matrix of the appropriate size.

> newtype IdMat a n = IdMat { runIdMat :: Matrix n n a }
>
> idMat :: (Nat n, Num a) => Matrix n n a
> idMat = runIdMat natCase
>
> instance Num a => NatCase (IdMat a) where
> caseZero = IdMat Nil
> caseSucc = IdMat (Cons (Cons 1 (vec 0)) (fmap (Cons 0) idMat))

*Vector_GADT> idMat :: Matrix Four Four Int
[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]

*Vector_GADT> idMat :: Matrix Two Three Int

:1:0:
Couldn't match `One' against `Zero'
  Expected type: Matrix Two Three Int
  Inferred type: Matrix Two Two a
In the expression: idMat :: Matrix Two Three Int
In the definition of `it': it = idMat :: Matrix Two Three Int
-- 
David Menendez <[EMAIL PROTECTED]> <http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Y in haskell?

2005-04-17 Thread David Menendez
Trevion writes:

> On 4/18/05, Lloyd Allison <[EMAIL PROTECTED]>
wrote:
> > Is it possible to define Y in Haskell (pref' H98) --
> > and get it to pass type checking?
> 
> I believe that 
> 
> y f = f (y f)
> 
> is the normal way to do it.

I've also seen this:

    y f = g
where g = f g
-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Control.Monad.Writer as Python generator

2005-04-13 Thread David Menendez
ChrisK writes:

> I was thinking to myself:
> What in Haskell would give me a "yield" command like a Python
> generator?
> 
> And the answer was "tell" in Control.Monad.Writer -- and I wrote some
> simple examples (see below).

Another possibility would be a continuation monad.

import Control.Monad.Cont

yield :: a -> Cont [a] ()
yield x = Cont (\c -> x : c ())

asGenerator :: Cont [a] v -> [a]
    asGenerator (Cont f) = f (const [])
-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Arrows GUI Library Based on GTK+

2005-03-19 Thread David Menendez
Kevin Atkinson writes:

> 
> What follows is my first attempt of using Arrows to create a GUI
> Library based on GTK+.  It uses many ideas from Fruit
> (http://haskell.org/fruit/). However it is based on discrete events
> rather than a continuous signal. The interface is only updated during
> an Event. It also ideas from Fudgets
> (http://www.md.chalmers.se/Cs/Research/Functional/Fudgets/), some of
> which were also used by Fruit.
> 
> To the best of my knowledge this has note been attempted before as
> Fruit is not based on an existing GUI.

Are you familiar with wxFruit[1]? It adapts Fruit to run on wxHaskell.

[1] <http://zoo.cs.yale.edu/classes/cs490/03-04b/bartholomew.robinson/>
-- 
David Menendez <[EMAIL PROTECTED]> <http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Type of y f = f . f

2005-02-28 Thread David Menendez
Jon Fairbairn writes:

> On 2005-02-28 at 18:03GMT Ben Rudiak-Gould wrote:
> > Pedro Vasconcelos wrote:
> >  >Jim Apple <[EMAIL PROTECTED]> wrote:
> >  >>Is there a type we can give to
> >  >>
> >  >>y f = f . f
> >  >>
> >  >>y id
> >  >>y head
> >  >>y fst
> >  >>
> >  >>are all typeable?
> >  >
> >  >Using ghci:
> >  >
> >  >Prelude> let y f = f.f
> >  >Prelude> :t y
> >  >y :: forall c. (c -> c) -> c -> c
> >  >
> >  >So it admits principal type (a->a) -> a->a. From this you can see
> >  >that (y head) and (y fst) cannot be typed, whereas (y id) can.
> > 
> > I think the OP's point is that all three of his examples make
> > sense, and the resulting functions would have Haskell types, yet
> > there doesn't seem to be a Haskell type which permits all three
> > uses of y.
> 
> The problem is that the type system needs to be checkable,
> so has to throw some information away.

There are type systems which can type this, but they have their own
quirks. For example, System E [1] would give us:

    y :: (a -> b & b -> c) -> a -> c

where "a & b" is the intersection of types "a" and "b". The advantage of
System E over, say, System F, is that type inferencing is decidable. The
downside is that the inferred types can be pretty long.

[1] <http://www.macs.hw.ac.uk/~sebc/>
-- 
David Menendez <[EMAIL PROTECTED]> <http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Help on Arrows

2005-01-15 Thread David Menendez
Georg Martius writes:

> Hi folks,
> 
> I would like to use Arrows, but I just can't figure out how to
> actually use them. I looked at various documentations including the
> API doc [1], the Wiki [2], [3], and some random pages on the net but
> didn't find a single simple example that tells me how to apply an
> Arrow to a value.

It depends on the type of the arrow. Arrows of type (->) can be applied
directly, because they're just plain functions. Arrows of type 'Kleisli
m' can be applied using a simple 'runKleisli' function.

runKleisli :: Kleisli m a b -> a -> m b
runKleisli (Kleisli f) = f

(I'm not sure why this isn't in Control.Arrow in the first place.)

Using your example arrow, we can use ($) and 'runKleisli' to coerce it
into functions of various types.

myAdd1A :: (Arrow a, Num b) => a b b
myAdd1A = arr (\x -> x + 1)

($) myAdd1A :: Num b => b -> b

runKleisli myAdd1A :: (Monad m, Num b) => b -> m b

More interesting arrows, like the signal processors in Yampa [4], may
not have a meaningful concept of application.

[4] <http://www.haskell.org/yampa/>
-- 
David Menendez <[EMAIL PROTECTED]> <http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


[Haskell] BBEdit syntax highlighting for Haskell

2004-08-30 Thread David Menendez
If anyone else is using BBEdit 8.0 on the Mac, I've put together a
simple language module for highlighting Haskell syntax.

<http://www.eyrie.org/~zednenem/sw/bbedit/haskell-syntax.plist>

To install, download the file above to ~/Application
Support/BBEdit/Language Modules and restart BBEdit.
-- 
David Menendez <[EMAIL PROTECTED]> | "In this house, we obey the laws
<http://www.eyrie.org/~zednenem>  |of thermodynamics!"
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Do the libraries define S' ?

2004-07-08 Thread David Menendez
Conor T McBride writes:

> As some of you know, I like them a lot too. In fact, if you have a
> return-like thing and an ap-like thing, you can make fmap as well.
> (Note that the return for the environment monad is none other than
> S's best friend K.)
> 
> So I got hacking, a little while ago...
> 
>infixl 9 <%>  -- my name for <# -- others have other names
>class Idiom i where
>  idi :: x -> i x
>  (<%>) :: i (s -> t) -> i s -> i t
> 
> I call them idioms because it's like having the apparatus
> of applicative programming, just in a different (perhaps impure)
> idiom.
> 
> [I only just found out that they show up under the name Sequence
>   in the experimental Control.Sequence module. I should have known.
>   It's part of the Arrow stuff, and these things are an interesting
>   species of Arrow. As far as I know, it was Ross Paterson who
>   identified them in the categorical jungle as weakly symmetric lax
>   monoidal functors.]

I've also seen this referred to as a pointed functor[1] and a
premonad[2].

So here's yet another definition of Monad:

class Functor f where
  fmap :: (a -> b) -> f a -> f b

class Functor p => Premonad p where
  return :: a -> p a

class Premonad m => Monad m where
  join  :: m (m a) -> m a
  (>>=) :: m a -> (a -> m b) -> m b
  
  join m  = m >>= id
  m >>= k = join (fmap k m)

[1] Composing Monads Using Coproducts 
<http://www.informatik.uni-bremen.de/~cxl/papers/icfp02.pdf>
[2] Composing Monads <http://www.cse.ogi.edu/~mpj/pubs/composing.html>
-- 
David Menendez <[EMAIL PROTECTED]> <http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


RE: [Haskell] Annoying naming clashes

2004-06-17 Thread David Menendez
Stefan Holdermans writes:

> Well, you've just identified the well-known trade-off between
> abstraction and induction. A language extension involving 'views' [4,
> 1, 3] has been proposed [2] to deal with this issue.

That proposal for views is eight years old. Has there been any movement
towards implementing it? Did some technical obsticle arise, or have
people simply been busy elsewhere?

> [2] Warren Burton, Erik Meijer, Patrick Sansom, Simon Thompson, and
> Philip Wadler. Views: An extension to Haskell pattern matching, 1996.
> http://www.haskell.org/development/views.html
-- 
David Menendez <[EMAIL PROTECTED]> <http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] IO, exceptions and error handling

2004-06-14 Thread David Menendez
Graham Klyne writes:

> Another approach that occurs to me is to introduce an error Monad
> along the lines of that described by Philip Wadler as "E" in his
> "Essence of functional programming" paper [1].  (Or just use Either
> as an error monad?, which is part of what I've been doing with my XML
> work.)

Control.Monad.Error defines a class MonadError and some instances that
provide the functionality of Wadler's E monad.

> The disadvantages I see here are: (a) it requires existing code to be
> modified to return the error monad value. (b) it imposes a strict
> sequencing on the order of computation, which as far as I can see is
> not necessary to achieve the required error handling.  For example, a
> computation that returns a result that is not actually used in a
> subsequent computation would still cause an exception;  e.g.
>  do { b <- f1   -- False
> ; c <- f2   -- raises exception
> ; d <- f3   -- value required
> ; return (if b then c else d)
> }
> (I know this could be coded differently to avoid the claimed problem,
> but to my mind it still illustrates unnecessary complexity compared
> with:
>  if f1 then f2 else f3
> In effect, it requires the programmer to figure out the lazy
> evaluation sequences instead of letting the Haskell system do it.)

I usually do that as:

> do b <- f1
>if b then f2 else f3

It's only slightly more complex, it's lazy, and it works with any monad.

But your general point is still valid.

--

As for bridging errors from one library to another, if you use
MonadError e m rather than a specific error monad, you can do something
along these lines:

> import Control.Monad.Error
> 
> data XmlError = X1 | X2 | X3 | XOther String
> deriving (Eq, Show)
> 
> instance Error XmlError where
>   strMsg = XOther
> 
> 
> data AppError = AppXmlError XmlError | AppOther String
> deriving (Eq, Show)
> 
> instance Error AppError where
>   strMsg = AppOther
> 
> --
> 
> xmlFunc :: (MonadError XmlError m)
> => String -> m String
> xmlFunc str = throwError X1
> 
> 
> appFunc :: (MonadError AppError m)
> => String -> m String
> appFunc s
>   = do s' <- mapError AppXmlError (xmlFunc s)
>return ("result: " ++ s')
> 
> 
> mapError :: (MonadError e m)
>  => (e' -> e) -> ErrorT e' m a -> m a
> mapError f m = runErrorT m >>= either (throwError . f) return
>
>   -- n.b. runErrorT :: ErrorT e m a -> m (Either e a)
>
> test :: String -> Either AppError String
> test = appFunc
-- 
David Menendez <[EMAIL PROTECTED]> <http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


[Haskell] Arrows and XML filters

2004-04-16 Thread David Menendez
I don't know if this has come up before. If it has, I'd be interested in
a link to the discussion.

Last week, I noticed that filters used in the Haskell XML Toolbox (and
elsewhere) are easily made into arrows. Specifically, for any filter

  f :: a -> [b]
  
we can write
  
  Kleisli f :: Kleisli [] a b


It then turns out that many of the filter combinators correspond exactly
to arrow combinators. For example:

  Kleisli (g `o` f) === Kleisli f >>> Kleisli g
  Kleisli (f .> g)  === Kleisli f >>> Kleisli g
  Kleisli (f +++ g) === Kleisli f <+> Kleisli g
  Kleisli this  === returnA
  Kleisli none  === zeroArrow

Similarly, for the functions 'cat' and 'seqF', we can write 

> asum :: ArrowPlus a => [a b c] -> a b c
> asum = foldr (<+>) zeroArrow
> 
> seqA :: Arrow a => [a b b] -> a b b
> seqA = foldr (>>>) returnA

And so forth.


The predicate combinators can't be made as general, but they still work
in an arrow framework.

> orElse :: Kleisli [] a b -> Kleisli [] a b -> Kleisli [] a b
> orElse (Kleisli f) (Kleisli g) =
>   Kleisli (\t -> let res = f t in if null res then g t else res)

The tree filters work similarly:

> type TFilterA node = Kleisli [] (NTree node) (NTree node)
> processChildren :: TFilterA node -> TFilterA node
> processChildren (Kleisli f) =
>   Kleisli (\(NTree n cs) -> [NTree n (concatMap f cs)])


I don't know if this has any practical value. (Perhaps for future XML
libraries?) If nothing else, it's given me some experience with and (I
hope) a better understanding of arrows.
-- 
David Menendez <[EMAIL PROTECTED]> <http://www.eyrie.org/~zednenem/>
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell