Re: [Haskell-cafe] Re: Typed Lambda-Expressions withOUT GADTs

2005-01-08 Thread Martin Sulzmann
Hi,

So far, we've seen GADTs encodings based on
the ideo of turning each (value) pattern clause 
into an (type class) instance declaration.

There's also another encoding based on the idea
of providing (value) evidence for type equality.
(Explored by example by quite a few people,
see upcoming paper for references).

A formal result can be found here:
A Systematic Translation of Guarded Recursive Data Types to
Existential Types
by Martin Sulzmann and Meng Wang
http://www.comp.nus.edu.sg/~sulzmann/

Example encodings for some of the
examples we've seen so far can be found below.

Martin

- Examples encodings ---

{-# OPTIONS -fglasgow-exts #-}

data E a b = E (a->b,b->a)
{-
data Sym env r 
= forall xx.(env = (r,xx)) => FirstSym
| forall env' a.(env=(a,env')) => NextSym (Sym env' r)
-}

data Sym env r 
= forall xx. FirstSym (E env (r,xx))
| forall env' a. NextSym (Sym env' r) (E env (a,env'))
{-
runSym :: Sym env r -> env -> r
runSym FirstSym (r,xx) = r
runSym (NextSym var) (a,env) = runSym var env
-}
-- have to play the pair trick because pattern doesn't match
runSym :: Sym env r -> env -> r
runSym (FirstSym (E (g,h))) pair {-(r,xx)-} = (fst (g pair))
runSym (NextSym var (E (g,h))) pair {-(a,env)-} = runSym var (snd (g
pair))

{-
data OpenExpression env r
= forall a r'.(r=(a->r')) => Lambda (OpenExpression (a',env) r')
| forall r'. Symbol (Sym env r)
| Constant r
| forall a. Lambda (OpenExpression env (a -> r))
   (OpenExpression env a)
-}

data OpenExpression env r
= forall a r'. Lambda (OpenExpression (a,env) r') (E r (a->r'))
| Symbol (Sym env r)
| Constant r
| forall a. Application (OpenExpression env (a -> r))
(OpenExpression env a)
{-
runOpenExpression :: OpenExpression env a -> env -> a
runOpenExpression (Constant r) _ = r
runOpenExpression (Application ar a) env = (runOpenExpression ar env)
(runOpenExpression a env)
runOpenExpression (Lambda exp) env = \a -> runOpenExpression exp
(a,env)
runOpenExpression (Symbol var) env = runSym var env
-}

runOpenExpression :: OpenExpression env a -> env -> a
runOpenExpression (Constant r) _ = r
runOpenExpression (Application ar a) env = (runOpenExpression ar env)
(runOpenExpression a env)
runOpenExpression (Lambda exp (E (g,h))) env = h (\a ->
runOpenExpression exp (a,env))
runOpenExpression (Symbol var) env = runSym var env

newtype Expression r = MkExpression (forall env. OpenExpression env r)

runExpression :: Expression r -> r
runExpression (MkExpression expr) = runOpenExpression expr () 

eid = E (id,id)
sym0 :: OpenExpression (a,env) a
sym0 = Symbol (FirstSym eid)

sym1 :: OpenExpression (a,(b,env)) b
sym1 = Symbol (NextSym (FirstSym eid) eid)

sym2 :: OpenExpression (a,(b,(c,env))) c
sym2 = Symbol (NextSym (NextSym (FirstSym eid) eid) eid)


k :: Expression (a -> b -> a)
-- k = \x.\y -> x = \.\.1
k = MkExpression (Lambda (Lambda sym1 eid) eid)

s :: Expression ((a -> b -> c) -> (a -> b) -> a -> c)
-- s = \x.\y.\z -> x z (y z) = \.\.\.2 0 (1 0)
s = MkExpression (Lambda (Lambda (Lambda (Application (Application
sym2 sym0) (Application sym1 sym0)) eid) eid) eid)


test3 = (runExpression s) (runExpression k) (runExpression k)
   {-# OPTIONS
-fglasgow-exts #-}
import Control.Monad.State (MonadState (..))
data E a b = E (a->b,b->a)

data State s a
  = forall b. Bind (State s a) (a -> State s b) (E a b)
  | Return a 
  | Get (E a s)
  | Put s (E a ()) 

runState :: State s a -> s -> (s,a)
runState (Return a) s = (s,a)
runState (Get (E (g,h))) s = (s,(h s))
runState (Put s (E (g,h))) _ = (s,(h ()))
runState (Bind (Return a) k (E (g,h))) s 
  = let --cast :: State s b -> State s a
cast (Return a) = Return (h a)
cast (Get (E (g',h'))) =  Get (E (\x-> g' (g x),\x->h (h' x))) 

cast (Put s (E (g',h'))) = Put s (E (\x->g' (g x),\x->h (h'
x)))
cast (Bind s' k' (E (g',h'))) = Bind (cast s') (\x->k' (g x))
(E (\x->g' (g x),\x->h (h' x)))
in runState (cast (k a)) s
runState (Bind (Get (E (g1,h1))) k (E (g,h))) s 
  = let cast (Return a) = Return (h a)
cast (Get (E (g',h'))) =  Get (E (\x-> g' (g x),\x->h (h' x))) 

cast (Put s (E (g',h'))) = Put s (E (\x->g' (g x),\x->h (h'
x)))
cast (Bind s' k' (E (g',h'))) = Bind (cast s') (\x->k' (g x))
(E (\x->g' (g x),\x->h (h' x)))
in runState (cast (k (h1 s))) s
runState (Bind (Put s (E (g1,h1))) k (E (g,h))) _  
  = let cast (Return a) = Return (h a)
cast (Get (E (g',h'))) =  Get (E (\x-> g' (g x),\x->h (h' x))) 

cast (Put s (E (g',h'))) = Put s (E (\x->g' (g x),\x->h (h'
x)))
cast (Bind s' k' (E (g',h'))) = Bind (cast s') (\x->k' (g x))
(E (\x->g' (g x),\x->h (h' x)))
in runState (cast (k (h1 ( s
runState (Bind (Bind m k1 (E (g1,h1))) k2 (E (g,h))) s 
  = runState m (\x -> Bind (k1 x) k2 (E (g,h))) s 


{-
instance Monad (State s) where
(>>=) = Bind
return = Return

in

[Haskell-cafe] Two fun things with GADTs

2005-01-08 Thread Ashley Yakeley
1. Reifying class instances

Easy to do, and useful sometimes:

  data MyMonad m where
MkMyMonad :: (Monad m) => MyMonad m

  myReturn :: MyMonad m -> a -> m a
  myReturn MkMyMonad = return

  myBind :: MyMonad m -> m a -> (a -> m b) -> m b
  myBind MkMyMonad = (>>=)

Note this may not yet be available in GHC CVS, see bug #1097046.


2. Casting among a limited set of types

  data Witness a where
BoolWitness :: Witness Bool
IntWitness :: Witness Int
ListWitness :: Witness a -> Witness [a]

  data ComposeT p q a = MkComposeT {unComposeT p (q a)}

  witnessCast :: Witness a -> Witness b -> p a -> Maybe (p b)
  witnessCast BoolWitness BoolWitness pa = Just pa;
  witnessCast IntWitness IntWitness pa = Just pa;
  witnessCast (ListWitness wa) (ListWitness wb) pla = 
fmap unComposeT (witnessCast wa wb (MkComposeT pla))
  witnessCast _ _ _ = Nothing;

  class Castable a where
witness :: Witness a

  instance Castable Bool where
witness = BoolWitness

  instance Castable Int where
witness = IntWitness

  instance (Castable a) => Castable [a] where
witness = ListWitness witness

  cast :: (Castable a,Castable b) => p a -> Maybe (p b)
  cast = witnessCast witness witness

  castOne :: (Castable a,Castable b) => a -> Maybe b
  castOne a = fmap runIdentity (cast (Identity a))

-- 
Ashley Yakeley, Seattle WA

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


[Haskell-cafe] Re: The Implementation of Functional Programming Languages

2005-01-08 Thread Ivan Boldyrev
On 8983 day of my life Simon Peyton-Jones wrote:
> I'm happy to announce that my out-of-print 1987 book,
>
>   The Implementation of Functional Programming Languages
>
> is now available online at
>
> http://research.microsoft.com/%7Esimonpj/papers/slpj-book-1987/index.htm
>
> Very many thanks to Marnie Montgomery, who did all the work.
>
> Happy reading

That's wonderful!!!

But I must admit that JPEG format is worst format for such
publication.  First, is blures images, that is OK for photos but
very bad for texts.  Second, it is not most compact format for
black-and-white images.

I tried to convert
http://research.microsoft.com/%7Esimonpj/papers/slpj-book-1987/IMAGES/IV.JPG
into different formats:


  71626 Янв  9 00:35 IV.JPG-- original
  10135 Янв  9 00:41 IV.png
   5880 Янв  9 00:40 IV.djvu


DjVu format is 12 times more compact, and PNG is 7 more compact!!!

I would be glad to help you with converting files and explaining their
advantages and disadvantages; feel free to contact me with e-mail.
Note, however, that JPG images are not proper for conversion source
because they are corrupted :(

-- 
Ivan Boldyrev

Outlook has performed an illegal operation and will be shut down.
If the problem persists, contact the program vendor.

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


Re: [Haskell-cafe] Guards (Was: Some random newbie questions)

2005-01-08 Thread Lemming
Jon Cast wrote:
Absolutely.  In Haskell's syntax, if-then-else-if interacts badly with
do notation, and Haskell lacks a direct analogy to Lisp's cond.
case () of
  () | p1 -> e1
 | p2 -> e2
 ...
No problem:
select :: a -> [(Bool, a)] -> a
select def = maybe def snd . List.find fst
Use it this way:
select defaultE
   [(p1, e1),
(p2, e2)]
Would be a nice Prelude function.
 parseCmd ln
   | Left err <- parse cmd "Commands" ln
 = BadCmd $ unwords $ lines $ show err
   | Right x <- parse cmd "Commands" ln
 = x
with the Haskell-98 alternative
 parseCmd ln = case parse cmd "Commands" ln of
   Left err -> BadCmd $ unwords $ lines $ show err
   Right x  -> x
Really, the second alternative is cleaner in my opinion.
Furthermore, guards are an extension of pattern matching, which means
you can write code like this:
 xn !! n | n < 0  = error "Prelude.(!!): Negative index"
 [] !! n  = error "Prelude.(!!): Index overflow"
 (x:xn) !! n | n == 0 = x
 (x:xn) !! n  = xn !! (n - 1)
Exactly one equation for each edge in the control-flow graph, which is
nice and not easily done (I'm not sure it's even possible) without
guards.
At least one guard can nicely be avoided:
(x:xn) !! n  =  if n == 0 then x else xn !! (n - 1)
But I see that guards can be used to let pattern matching fail.

Pattern guards are also nice for implementing ‘views’:
 -- | Convert an 'XMLData' into an equivalent application of
 -- 'Balanced', if possible.  In any case, return an equivalent data
 -- structure.
 balance (Balanced es) = Balanced es
 balance (LeftLeaning (LeftBalanced e:es))
   | Balanced es' <- balance (LeftLeaning es)
   = Balanced (e:es')
I don't know what this means exactly, but I think I can transform it 
formally to:

balance e'@(LeftLeaning (LeftBalanced e:es)) =
   case balance (LeftLeaning es) of
  Balanced es' -> Balanced (e:es')
  _ -> e'
This way it is more clear for me, that 'balance' can return something 
different from 'Balanced' and that the data is returned unchanged in 
this case.

 balance (LeftLeaning []) = Balanced []
 balance (RightLeaning [("", "", es)]) = Balanced es
 balance (RightLeaning []) = Balanced []
 balance e = e

Well, I could never do without them.
Sometimes I see people abusing guards, e.g. they write a 'length x == 1' 
guard, where the pattern '[x0]' would be clearly the better choice. So 
I'm always thinking twice before using a guard.
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Some random newbie questions

2005-01-08 Thread Benjamin Pierce
Many thanks to everyone for the very helpful answers to my queries!

- Benjamin


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


Re: [Haskell-cafe] Re: Hugs vs GHC (again) was: Re: Some random newbiequestions

2005-01-08 Thread David Roundy
On Sat, Jan 08, 2005 at 08:08:38AM +, Aaron Denney wrote:
> I suppose I wouldn't be too upset at using the locale information, but
> defaulting to UTF-8, rather than ASCII for unset character set
> information.

But if we default to a UTF-8 encoding, then there could be decoding
failures when attempting to read a file.  You have to consider both the
possibility that characters aren't expressible in a given encoding and the
possibility that files aren't expressible in a given encoding.  ASCII (or
iso-whatever) has the advantage that at least every file is readable.

But as you say, really what we need is a binary IO system first, and then
the character-based IO can do whatever it likes without breaking things
(since it'll only be used by programs that actually want unicode coding).
-- 
David Roundy
http://www.darcs.net
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Re: Hugs vs GHC (again) was: Re: Some random newbiequestions

2005-01-08 Thread Aaron Denney
On 2005-01-07, Simon Marlow <[EMAIL PROTECTED]> wrote:
>  - Can you use (some encoding of) Unicode for your Haskell source files?
>I don't think this is true in any Haskell compiler right now.

I assume this won't be be done until the next one is done...

>  - Can you do String I/O in some encoding of Unicode?  No Haskell
>compiler has support for this yet, and there are design decisions
>to be made.  Some progress has been made on an experimental prototype
>(see recent discussion on this list).

Many of the easy ways to do this that I've heard proposed make the
current hacks for binary IO fail.  IMHO, we really, really, need a
standard, supported way to do binary IO.  If I can read in and output
octets, then I can implement unicode handling on top of that.  In fact
it would let a bunch of the proposed ideas for unicode support can
be implemented in pure haskell and have API details hashed out and
polished.

For unix, there are couple different tacks one could take.  The locale
system is standard, and does work, but is ugly and a pain to work with.
In particular, it's another (set of) global variables.  And what do you
do with a character not expressible in the current locale?

I'd like to possibility of different character sets for different files,
for example.

I suppose I wouldn't be too upset at using the locale information, but
defaulting to UTF-8, rather than ASCII for unset character set
information.

For win32, I really don't know the options.

>  - What about Unicode FilePaths?  This was discussed a few months ago
>on the haskell(-cafe) list, no support yet in any compiler.

This is tricky, because most systems don't have such a thing terribly
standard.

For win32, it is standardized and should be wrappable fairly easily, but
I don't know that I'd want to base my model on that.

For unix, again, there is the locale system, with, again, the problem
of unrepresentable characters.  Traditionally systems have essentially
said "file names are zero-terminated strings of bytes that may not
contain character 47, which is used to seperate directory names", and
the interpretation as a matter of _names_ and _characters_ was entirely
a matter up to the terminals (or graphical programs, eventually) for
display and programs for manipulation.  

-- 
Aaron Denney
-><-

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