Re: Functional dependencies can return kinds, type families cannot

2014-02-13 Thread Richard Eisenberg

On Feb 13, 2014, at 4:28 AM, José Pedro Magalhães j...@cs.uu.nl wrote:

 
 The most interesting part here is the functional dependency fs - k, where k 
 is a kind variable!
 If this is not a bug (and it does seem to work as I expect it to), then could 
 we have type families
 return kinds too?...

Yes, I ran into this a while ago. A function dependency on a kind seems to work 
remarkably well.

Can we have type families that return kinds? No. Well, not yet. Functional 
dependencies inform type inference but don't produce any evidence in Core -- a 
dependency is only ever used to eliminate ambiguity. On the other hand, a type 
family does produce evidence (in the form of a type coercion) in Core, and kind 
coercions turn out to be challenging. How challenging? See System FC with 
Explicit Kind Equality, ICFP '13 
(http://www.cis.upenn.edu/~eir/papers/2013/fckinds/fckinds-extended.pdf)

How does this difference between fundeps and type families manifest itself? 
Type families work much better with GADTs. I don't have an example to hand, but 
if you're doing GADT programming, using fundeps won't get you very far. That's 
because the GADTs use the Core coercions internally... and the fundeps don't 
produce them.

Nevertheless, having done the theory behind a Core language with explicit kind 
coercions, I'm now in the midst of implementing (on a branch -- don't expect 
anything soon!) type inference for that Core language. In effect, it would be 
the resolution of GHC bug #7961 (https://ghc.haskell.org/trac/ghc/ticket/7961), 
but with fairly far-reaching consequences in the implementation. So, if all 
goes well, we'll have type families returning kinds at some point in the 
not-too-distant future.

Richard___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: [Haskell-cafe] Re: Functional dependencies and Peano numbers (and hoogle-bug?)

2010-07-15 Thread Oscar Finnsson
Thanks for the great feedback. The bijective example was especially interesting.

While reading Fun with Type Functions I notices GNum as an
interesting alternative to the Num type class but I couldn't find any
such package on hackagedb. Do anyone know if there is anything like
GNum on hackagedb?



On an unrelated note:

I hoogled to (i.e. http://haskell.org/hoogle/?hoogle=to) and just
got a blank page. Nothing. Nil (not even html.../html). Is this a
bug or a feature? :) The reason I hoogled it was because I'm
searching for something like explicit casting found in many other
languages, something similar to

 class To f t where
   to :: f - t

 instance To a a where
   to x = x

 instance (Real a, Fractional b) = To a b where
   to = realToFrac

 instance (Read a) = To String (Maybe a) where
   to = maybeRead  -- not from cgi :)

so I can write something like

 (23.2 `to`) :: Maybe Double

or

 ((42 :: Integer) `to`) :: Float

Anyone made a module/package that solves this problem already? I
cannot be the first that needs generic type safe conversion... .

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


Re: [Haskell-cafe] Re: Functional dependencies and Peano numbers (and hoogle-bug?)

2010-07-15 Thread wren ng thornton

Oscar Finnsson wrote:

Anyone made a module/package that solves this problem already? I
cannot be the first that needs generic type safe conversion... .


There's a restricted version in logfloat:Data.Numer.RealToFrac[1] which 
generalizes the Prelude's realToFrac to improve performance and correctness.


To do much more than that you'll probably have to use something like 
Data.Data, Data.Typeable, or similar. Generally speaking, arbitrary 
casts from one type to another go against Haskell ideology because they 
don't make a lot of sense. Often times there are multiple intelligible 
ways to convert between two fixed types, so how can we choose? Things 
like realToFrac, read, show, etc make sense precisely because they are 
more restricted and therefore make explicit the semantic intentions of 
how the conversion should be done.



[1] 
http://hackage.haskell.org/packages/archive/logfloat/0.12.1/doc/html/Data-Number-RealToFrac.html


--
Live well,
~wren
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Functional dependencies and Peano numbers

2010-07-13 Thread Brent Yorgey
On Sun, Jul 11, 2010 at 12:43:47AM +0200, Jose A. Ortega Ruiz wrote:
 On Sat, Jul 10 2010, wren ng thornton wrote:
 
 
 [...]
 
 
  Yes, you can add multiple dependencies. The syntax is to use , after
  the first |.
 
  While having eight parameters is surely a desperate need for
  refactoring, there are times when you'd want multiple dependencies.
  For example, you can say
 
  class F a b | a - b, b - a where...
 
  to express a bijective function on types (that is, for every pair of A
  and B, if you know one of them then you know what the other must be
  uniquely).
 
 I know i should read the relevant articles, but how would one express
 such a bijection using type families?

You would just create two type families, one for each direction of the
mapping:

  type family F1 a :: *
  type instance F1 Int = Bool
  type instance F1 ...

  type family F2 a :: *
  type instance F2 Bool = Int
  type instance F2 ...

Of course, this is not quite the same thing, since with the MPTC
version we are guaranteed to get a bijection, but there is nothing
forcing F1 and F2 to have anything to do with one another (for example
I could have written type instance F2 Char = Int).  But I don't know
whether this would make a difference in practice.

-Brent

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


[Haskell-cafe] Re: Functional dependencies and Peano numbers

2010-07-10 Thread Jose A. Ortega Ruiz
On Sat, Jul 10 2010, wren ng thornton wrote:


[...]


 Yes, you can add multiple dependencies. The syntax is to use , after
 the first |.

 While having eight parameters is surely a desperate need for
 refactoring, there are times when you'd want multiple dependencies.
 For example, you can say

 class F a b | a - b, b - a where...

 to express a bijective function on types (that is, for every pair of A
 and B, if you know one of them then you know what the other must be
 uniquely).

I know i should read the relevant articles, but how would one express
such a bijection using type families?

TIA,
jao
-- 
You err by thinking simplicity and elegance are mostly
cosmetic.  Simplicity and elegance are overwhelmingly
practical virtues.
  - William D Clinger, comp.lang.scheme

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


[Haskell-cafe] Re: Functional Dependencies Help

2010-05-01 Thread John Creighton


On Apr 30, 6:18 pm, John Creighton johns2...@gmail.com wrote:
 On Apr 29, 7:47 am, John Creighton johns2...@gmail.com wrote:

  I've been trying to apply some stuff I learned about functional
  dependencies, but I run into one of two problems. I either end up with
  inconsistent dependencies (OverlappingInstances  doesn't seem to
  apply) or I end up with infinite recursion. I want to be able to do
  simple things like if a is a subset of b and b is a subset of c then a
  is a subset of c. If a is a is a subset of b and b is a c then a is a
  c.

  Before I added the equality functions I had infinite recursion. Once I
  put them them in then I have trouble with overlapping instances.

 I've been doing some reading and I think the following is an
 improvement but I end up hanging the compiler so I can't tell what the
 errors are. I'll see if their are any trace options that might be
 helpfully for GHC.

So bellow I'll post the latest version of my code but first the errors
which seem very strange to me:



could not deduce (IsSuperSet'
 isanimal iseq isanimal iseq1 (a - b - c3) )
   from the context (IsSuperSet a b c2,
 Typeeq a b iseq1,
 TypeEq Animal b isaninmal,
 IsSuperSet' isanimal iseq1 a b c3)
   arising from a use of 'isSuperSet'' at logicp2.hs:92:25-74
   Possible fix:
  add (IsSuperSet'
  isanimal iseq isanimal iseq1 (a - b - c3)) to context
of the declaration
  or add an instance delaration for
  (IsSuperSet' isanimal iseq isanimal iseq1 (a - b - c3))
   In the expression:
  (isSuperSet' (u :: isanimal) (u :: iseq) (a :: a)
(b ::b)) :: c3
   In the definition of 'isSuperset':
   isSuperset a b
= (isSuperSet' (u :: isanimal) (u :: iseq) (a ::
a) (b :: b))
   in the instance delaration for 'IsSuperSet a b c3'



Now what is strange about these errors, is the type signature haskell
is asking me to supply instance declarations for. For instance

  add (IsSuperSet'
  isanimal iseq isanimal iseq1 (a - b - c3)) to context
of the declaration

Why are the first and the third argument the same. Moreover why do the
third and forth arguments look like types related to my Boolean data
types. I see nothing in my code that could result in Haskell needing
this type signature. Also I'm not entirely sure about the (a - b -
c3). Is this the normal way for Haskell to show the type signature of
functional dependencies.  My code is bellow and was compiled on GHCi.



{-# LANGUAGE EmptyDataDecls,
 MultiParamTypeClasses,
 ScopedTypeVariables,
 FunctionalDependencies,
 OverlappingInstances,
 FlexibleInstances,
 UndecidableInstances#-}

{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}


data Noun = Noun deriving (Show) --15
data Verb = Verb deriving (Show) --
data Adjactive = Adjactive deriving (Show)

data Animal=Animal deriving (Show)
data Feline=Feline deriving (Show) --20
data Cat = Cat deriving (Show)

data Taby_Cat=Taby_Cat deriving (Show)
data T=T deriving (Show)
data F=F deriving (Show) --25
--data Z=Z
--data S i = S i
--type One = S Z
--type Zero = Z
class Isa a b c | a b-c where isa::a-b-c --30

instance Isa Animal Noun T where isa a b = T --



class Parrent a b| a-b where -- Specific Cases
parrent :: a-b --

instance Parrent Cat Feline where --
   parrent a = Feline --40
instance Parrent Feline Animal where --
   parrent a= Animal --




class TypeOr a b c|a b-c where
   typeOr :: a-b-c
instance TypeOr T T T where
   typeOr a b = T --50
instance TypeOr T F T where
   typeOr a b = T
instance TypeOr F T T where
   typeOr a b = T
instance TypeOr F F T where
   typeOr a b = T

class TypeEq' () x y b = TypeEq x y b | x y - b
instance TypeEq' () x y b = TypeEq x y b
class TypeEq' q x y b | q x y - b --60
class TypeEq'' q x y b | q x y - b

instance TypeCast b T = TypeEq' () x x b
instance TypeEq'' q x y b = TypeEq' q x y b
instance TypeEq'' () x y F

-- see http://okmij.org/ftp/Haskell/typecast.html
class TypeCast   a b   | a - b, b-a   where typeCast   :: a - b
class TypeCast'  t a b | t a - b, t b - a where typeCast'  :: t-a-
b
class TypeCast'' t a b | t a - b, t b - a where typeCast'' :: t-a-
b --70

instance TypeCast'  () a b = TypeCast a b where typeCast x =
typeCast' () x
instance TypeCast'' t a b = TypeCast' t a b where typeCast' =
typeCast''
instance TypeCast'' () a a where typeCast'' _ x  = x

-- overlapping instances are used only for ShowPred
class EqPred a flag | a-flag where {}

  -- Used only if the other
  -- instances don't apply -- 80

class IsSuperSet a b c | a b - c where -- General Definition
isSuperSet :: a-b-c


[Haskell-cafe] Re: Functional Dependencies Help

2010-04-30 Thread John Creighton

On Apr 29, 7:47 am, John Creighton johns2...@gmail.com wrote:
 I've been trying to apply some stuff I learned about functional
 dependencies, but I run into one of two problems. I either end up with
 inconsistent dependencies (OverlappingInstances  doesn't seem to
 apply) or I end up with infinite recursion. I want to be able to do
 simple things like if a is a subset of b and b is a subset of c then a
 is a subset of c. If a is a is a subset of b and b is a c then a is a
 c.

 Before I added the equality functions I had infinite recursion. Once I
 put them them in then I have trouble with overlapping instances.

I've been doing some reading and I think the following is an
improvement but I end up hanging the compiler so I can't tell what the
errors are. I'll see if their are any trace options that might be
helpfully for GHC.
{-# LANGUAGE EmptyDataDecls,
 MultiParamTypeClasses,
 ScopedTypeVariables,
 FunctionalDependencies,
 FlexibleInstances #-}

{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-} --10
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}


data Noun = Noun deriving (Show) --15
data Verb = Verb deriving (Show) --
data Adjactive = Adjactive deriving (Show)

data Animal=Animal deriving (Show)
data Feline=Feline deriving (Show) --20
data Cat = Cat deriving (Show)

data Taby_Cat=Taby_Cat deriving (Show)
data T=T deriving (Show)
data F=F deriving (Show) --25
--data Z=Z
--data S i = S i
--type One = S Z
--type Zero = Z
class Isa a b c | a b-c where isa::a-b-c --30

instance Isa Animal Noun T where isa a b = T --



class Parrent a b| a-b where -- Specific Cases
parrent :: a-b --

instance Parrent Cat Feline where --
   parrent a = Feline --40
instance Parrent Feline Animal where --
   parrent a= Animal --




class TypeOr a b c|a b-c where
   typeOr :: a-b-c
instance TypeOr T T T where
   typeOr a b = T --50
instance TypeOr T F T where
   typeOr a b = T
instance TypeOr F T T where
   typeOr a b = T
instance TypeOr F F T where
   typeOr a b = T

class TypeEq' () x y b = TypeEq x y b | x y - b
instance TypeEq' () x y b = TypeEq x y b
class TypeEq' q x y b | q x y - b --60
class TypeEq'' q x y b | q x y - b

instance TypeCast b T = TypeEq' () x x b
instance TypeEq'' q x y b = TypeEq' q x y b
instance TypeEq'' () x y F

-- see http://okmij.org/ftp/Haskell/typecast.html
class TypeCast   a b   | a - b, b-a   where typeCast   :: a - b
class TypeCast'  t a b | t a - b, t b - a where typeCast'  :: t-a-
b
class TypeCast'' t a b | t a - b, t b - a where typeCast'' :: t-a-
b --70

instance TypeCast'  () a b = TypeCast a b where typeCast x =
typeCast' () x
instance TypeCast'' t a b = TypeCast' t a b where typeCast' =
typeCast''
instance TypeCast'' () a a where typeCast'' _ x  = x

-- overlapping instances are used only for ShowPred
class EqPred a flag | a-flag where {}

  -- Used only if the other
  -- instances don't apply -- 80

class IsSuperSet a b c | a b-c where -- General Definition
isSuperSet :: a-b-c

--instance (TypeEq b Animal T,TypeEq c F T)=IsSuperSet a b c where
--85
--   isSuperSet a b = F --
u=undefined
instance (
   TypeEq a b iseq, --90
   TypeEq Animal b isaninmal,
   IsSuperSet' isaninmal iseq a b c3 --
 ) =
 IsSuperSet a b c3 where --
 isSuperSet a b=(isSuperSet' (u::isaninmal) (u::iseq) (a::a)
(b::b))::c3

class IsSuperSet' isanimal iseq a b c| isanimal iseq a b-c where
isSuperSet' :: a-b-c

instance IsSuperSet' isanimal T a b T where
   isSuperSet' a b = T

instance (Parrent b d, IsSuperSet a b c)=IsSuperSet' F F a b c where
   isSuperSet' a b = (isSuperSet a ((parrent (b::b)::d)))::c

instance IsSuperSet' T F a b F where
   isSuperSet' a b = F


class ToBool a where
   toBool :: a-Bool

instance ToBool T where
   toBool a = True

instance ToBool F where
   toBool a = False

myCat=Cat
bla=isSuperSet Animal Cat
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Re: Functional dependencies conflict between instance declarations

2007-09-12 Thread Stefan Monnier
 Never mind, that GHC compiler was again more clever than me, sigh.
 That's really frustrating about Haskell: the compiler captures so many
 errors at compile time, that newbies hardly get anything done, it's
 a constant battle against the errors. But once it compiles, it usually
 works at runtime :-)
 This is what I love about Haskell: If it typechecks, it probably does the
 thing you meant it to.  I've never seen any other language like
 it.  It's amazing!

Next stop: Coq, where the fight with the type checker is so much more
difficult that when the code finally type checks you don't even need to
run it at all.


Stefan

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


RE: [Haskell-cafe] Re: Functional dependencies conflict between instance declarations

2007-09-12 Thread bf3
Are you kidding, or has automatic proving of programs evolved that far?

Anyway, for my sector, videogames, proving if something works correctly is
subjective, it's very hard to check if the gameplay of a game is good
enough since that involves human fuzzy judgement ;-)  Although this might
just be statistics, so can be proven too! Aaarrrggg, soon we're all out
of job ;-)

Peter

-Original Message-
From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] On Behalf Of Stefan Monnier
Sent: Wednesday, September 12, 2007 7:06 PM
To: haskell-cafe@haskell.org
Subject: [Haskell-cafe] Re: Functional dependencies conflict between
instance declarations

 Never mind, that GHC compiler was again more clever than me, sigh.
 That's really frustrating about Haskell: the compiler captures so many
 errors at compile time, that newbies hardly get anything done, it's
 a constant battle against the errors. But once it compiles, it usually
 works at runtime :-)
 This is what I love about Haskell: If it typechecks, it probably does the
 thing you meant it to.  I've never seen any other language like
 it.  It's amazing!

Next stop: Coq, where the fight with the type checker is so much more
difficult that when the code finally type checks you don't even need to
run it at all.


Stefan

___
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: Functional dependencies conflict between instance declarations

2007-09-12 Thread Andrew Coppin

[EMAIL PROTECTED] wrote:

Are you kidding, or has automatic proving of programs evolved that far?

Aaarrrggg, soon we're all out of job ;-)
  


Experts have been proclaiming this since high-level programming was 
invented many decades ago. We're still waiting. ;-)


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


[Haskell] Re: Functional dependencies and type inference (2)

2005-12-06 Thread Stefan Monnier
  instance CpsForm t t where
 This can't be right, can it?
 In general no: the CPS of a function certainly doesn't fit the above
 pattern. So, if the source language has abstractions (the language in
 the original message didn't), we have to add another instance for
 CpsForm.

But any other instance will cause problem because the second type won't be
functionally dependent on the first any more.  Or do you suggest we remove
the functional dependency?


Stefan

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


[Haskell] Re: Functional dependencies and type inference (2)

2005-12-04 Thread oleg

Stefan Monnier wrote:
  instance CpsForm t t where

 This can't be right, can it?

In general no: the CPS of a function certainly doesn't fit the above
pattern. So, if the source language has abstractions (the language in
the original message didn't), we have to add another instance for
CpsForm. Actually I started designing such a general typeful CPS of a
language with abstractions, applications (and perhaps even call/cc),
but then I ran out of time...

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


[Haskell] Re: Functional dependencies and type inference (2)

2005-12-03 Thread Stefan Monnier
 instance CpsForm t t where

This can't be right, can it?
After CPS conversion a term of type a - b won't have type a - b
but rather something like a * (b - c) - c.


Stefan

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


[Haskell] Re: Functional dependencies and type inference (2)

2005-11-30 Thread oleg

Louis-Julien Guillemette wrote:
 Say we are using a GADT to represent a simple language of boolean
 constants and conditionals,

 data Term a where
B:: Bool - Term Bool
Cnd  :: Term Bool - Term t - Term t - Term t

 and we would like to perform a type-safe CPS conversion over this
 language. We encode the relationship between the types in the source
 language and those in the CPS-converted language using a class and a
 fundep:

Here's the code that seems to do what you wished. Liberty is taken
to extend the language so we can CPS convert more interesting terms.

Here are the tests

 term1 = Cnd (Cnd (B True) (B False) (B False)) (B True) (B False)
 test1 = shw (cps term1 id) 

*CPS test1
Cnd (B True)(Cnd (B False)(B True)(B False))(Cnd (B False)(B True)(B False))

 term2 = Cnd (Cmp (Cnd (B True) (I 1) (I 2)) (I 3)) 
   (B True) (Cmp (B True) (B False))
 test2 = shw (cps term2 id) 

*CPS test2
Cnd (B True)(Cnd (Cmp (I 1)(I 3))(B True)(Cmp (B True)(B False)))
 (Cnd (Cmp (I 2)(I 3))(B True)(Cmp (B True)(B False)))

The code:

{-# OPTIONS -fglasgow-exts #-}
{-# OPTIONS -fallow-undecidable-instances #-}

module CPS where

data Term a where
   B:: Bool - Term Bool
   Cnd  :: Term Bool - Term t - Term t - Term t
   I:: Int - Term Int
   Cmp  :: Term t - Term t - Term Bool

-- Note the polymorphic answertype
class CpsForm t cps_t | t - cps_t where
cps :: Term t - (Term cps_t - Term w) - Term w

instance CpsForm t t where
cps (B b) c = c (B b)
cps (I b) c = c (I b)
cps (Cnd p q r) c = cps p (\p' - Cnd p' (cps q c) (cps r c))
cps (Cmp p q) c = cps p (\p' - cps q (\q' - c (Cmp p' q')))

shw:: Term t - String - String
shw (B t) = (B ++) . shows t
shw (I t) = (I ++) . shows t
shw (Cnd p q r) = (Cnd ++) 
  . (showParen True (shw p))
  . (showParen True (shw q)) 
  . (showParen True (shw r)) 
shw (Cmp p q) = (Cmp ++) 
. (showParen True (shw p))
. (showParen True (shw q)) 

term1 = Cnd (Cnd (B True) (B False) (B False)) (B True) (B False)
test1 = shw (cps term1 id) 

term2 = Cnd (Cmp (Cnd (B True) (I 1) (I 2)) (I 3)) 
(B True) (Cmp (B True) (B False))
test2 = shw (cps term2 id) 
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


RE: Functional Dependencies

2005-08-17 Thread Simon Peyton-Jones
|  class C a b | a - b
|  instance C Int Bool
| 
|  f :: forall a. C Int a = a - a
|  f x = x
| 
|  GHC rejects the type signature for f, because we can see that 'a'
*must
|  be* Bool, so it's a bit misleading to universally quantify it.
| 
| Ok, maybe this is a reasonable choice. But why does the attached
program work?
| ghci presents a unique type for the universal quantified function
'eight':
| 
| *Add :t eight
| eight :: Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))

From the instance declaration
instance Fib Zero (Succ Zero)
we get the improvement rule
Fib Zero a == a=(Succ Zero)
We get a similar rule from 
instance Fib (Succ Zero) (Succ Zero)
But the instance declaration
instance (Fib n fib_n,
  Fib (Succ n) fib_s_n,
   Add fib_n fib_s_n sum
  ) = Fib (Succ (Succ n)) sum
Fib Zero a
gives only
Fib Zero a === exists b. b=a
which does nothing useful.

So when GHC sees the type signature, it's quite happy.  No improvement
takes place.  If you compile Fib with -ddump-types you'll see it gets
the type you specify.


HOWEVER, when you say :t eight, GHC does not simply report the type of
eight.  You can type an arbitrary expression there (e.g. :t (reverse
hello)).  So GHC typechecks the expression eight.  So it
instantiates its type, and then tries to solve the constraint (Fib (Succ
(Succ...)) n).  Now it must use the instance declarations to simplify
it, and in doing so that exposes more constraints that do force n to be
the type you get.  


I agree this is desperately confusing, and I'm not saying that GHC is
doing the Right Thing here; but I wanted to explain what it is doing.
Functional dependencies are very slippery.  I do not think their
behaviour in GHC is necessarily best, nor is their exact behaviour
specified anywhere, but I do think the behaviour is consistent.

My current belief is that fundeps are too slippery to be given to
programmers at all.   They are not a good way to express type-level
computation.  Perhaps associated types might be a better way to express
this stuff (see my home page).

Simon

___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Functional Dependencies

2005-08-17 Thread Dirk Reckmann
Am Dienstag, 16. August 2005 19:45 schrieb Iavor Diatchki:
 Hello,
 I am not sure what GHC is doing, it certainly seems to be
 inconsistent.  In Hugs both the examples work.  In case you are
 interested, here is how you can get a version that works in
 both Hugs and GHC (I just modified your code a little):

[snip]

Introducing all these undefined functions is indeed a nice trick - thanks for 
this hint!

Ciao,
  Dirk
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Functional Dependencies

2005-08-16 Thread Keean Schupke
Picked up on this late... I have working examples of add etc under 
ghc/ghci...
I can't remeber all the issues involved in getting it working, but I can 
post the

code for add if its any use?

   Keean.

Dirk Reckmann wrote:


Am Donnerstag, 11. August 2005 11:41 schrieb Simon Peyton-Jones:
 


You raise a vexed question, which has been discussed a lot.  Should this
typecheck?

class C a b | a - b
instance C Int Bool

f :: forall a. C Int a = a - a
f x = x

GHC rejects the type signature for f, because we can see that 'a' *must
be* Bool, so it's a bit misleading to universally quantify it.
   



Ok, maybe this is a reasonable choice. But why does the attached program work? 
ghci presents a unique type for the universal quantified function 'eight':


*Add :t eight
eight :: Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))

Best regards,
 Dirk

 


Simon

| -Original Message-
| From: [EMAIL PROTECTED]

[mailto:glasgow-haskell-users-

| [EMAIL PROTECTED] On Behalf Of Dirk Reckmann
| Sent: 21 July 2005 10:30
| To: glasgow-haskell-users@haskell.org
| Subject: Functional Dependencies
|
| Hello everybody!
|
| I wanted to have some fun with functional dependencies (see
| http://www.cs.chalmers.se/~hallgren/Papers/wm01.html), and tried some
| examples from this paper as well as some own experiments. The idea is

to use

| the type checker for computations by abuse of type classes with

functional

| dependencies.
|
| The example in the attached file is taken from the above paper. Due to

the

| functional dependencies, I expected the type of seven to be uniquely
| determined to be (Succ (Succ (Succ ...))), i. e. seven, but ghc

(version 6.4)

| gives me following error message:
|
| Add.hs:14:0:
| Couldn't match the rigid variable `a' against `Succ s'
|   `a' is bound by the type signature for `seven'
|   Expected type: Succ s
|   Inferred type: a
| When using functional dependencies to combine
|   Add (Succ n) m (Succ s), arising from the instance declaration

at

| Add.hs:11:0
|   Add (Succ (Succ (Succ Zero))) (Succ (Succ (Succ (Succ Zero

a,

| arising from the type signature for `seven' at Add.hs:13:0-77
| When generalising the type(s) for `seven'
|
| However, using the definition of Add to define Fibonacci numbers does

work,

| and a similar function declaration can be used to compute numbers by

the type

| checker.
|
| The same definition of Add works in Hugs...
|
| So, is this a bug in ghc, or am I doing something wrong?
|
| Thanks in advance,
|   Dirk Reckmann
   




{-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-}

module Add where

data Zero
data Succ n

class Add n m s | n m - s

instance Add Zero m m
instance Add n m s = Add (Succ n) m (Succ s)

class Fib n f | n - f

instance Fib Zero (Succ Zero)
instance Fib (Succ Zero) (Succ Zero)
instance (Fib n fib_n,
 Fib (Succ n) fib_s_n,
 Add fib_n fib_s_n sum
) = Fib (Succ (Succ n)) sum

eight :: Fib (Succ (Succ (Succ (Succ (Succ Zero) n = n
eight = undefined
   




___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
   



___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Functional Dependencies

2005-08-16 Thread Dirk Reckmann
Hello Keean!

Am Dienstag, 16. August 2005 13:48 schrieb Keean Schupke:
 Picked up on this late... I have working examples of add etc under
 ghc/ghci...
 I can't remeber all the issues involved in getting it working, but I can
 post the
 code for add if its any use?

Yes, that would be nice. I'd like to see 'add' working... However, after each 
answer to my posting, I get more confused. Simon Peyton-Jones took all of my 
hope to get it working, because ghc doesn't like universal quantified but 
uniquely idetified types (at least, this is my understanding of his email). 
Now you have a working 'add' typelevel program. And the most confusing part 
for me is, that my fibonacci number program works, even though it makes use 
of the not working version of add.

So, I'm really looking forward to your version!

Ciao,
  Dirk
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Functional Dependencies

2005-08-16 Thread Iavor Diatchki
Hello,
I am not sure what GHC is doing, it certainly seems to be
inconsistent.  In Hugs both the examples work.  In case you are
interested, here is how you can get a version that works in
both Hugs and GHC (I just modified your code a little):

{-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-}

module Add where

data Zero;  zero = undefined :: Zero
newtype Succ n  = Succ n

class Add n m s | n m - s where
  add :: n - m - s
  add  = undefined

instance Add Zero m m
instance Add n m s = Add (Succ n) m (Succ s)

class Fib n f | n - f where
  fib :: n - f
  fib = undefined

instance Fib Zero (Succ Zero)
instance Fib (Succ Zero) (Succ Zero)
instance (Fib n fib_n,
  Fib (Succ n) fib_s_n,
  Add fib_n fib_s_n sum
 ) = Fib (Succ (Succ n)) sum

eight = fib (Succ (Succ (Succ (Succ (Succ zero)
two   = add (Succ zero) (Succ zero)


*Add :t eight
eight :: Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))
*Add :t two
two :: Succ (Succ Zero)

-Iavor

On 8/16/05, Dirk Reckmann [EMAIL PROTECTED] wrote:
 Hello Keean!
 
 Am Dienstag, 16. August 2005 13:48 schrieb Keean Schupke:
  Picked up on this late... I have working examples of add etc under
  ghc/ghci...
  I can't remeber all the issues involved in getting it working, but I can
  post the
  code for add if its any use?
 
 Yes, that would be nice. I'd like to see 'add' working... However, after each
 answer to my posting, I get more confused. Simon Peyton-Jones took all of my
 hope to get it working, because ghc doesn't like universal quantified but
 uniquely idetified types (at least, this is my understanding of his email).
 Now you have a working 'add' typelevel program. And the most confusing part
 for me is, that my fibonacci number program works, even though it makes use
 of the not working version of add.
 
 So, I'm really looking forward to your version!
 
 Ciao,
   Dirk
 ___
 Glasgow-haskell-users mailing list
 Glasgow-haskell-users@haskell.org
 http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Functional Dependencies

2005-08-15 Thread Dirk Reckmann
Am Donnerstag, 11. August 2005 11:41 schrieb Simon Peyton-Jones:
 You raise a vexed question, which has been discussed a lot.  Should this
 typecheck?

   class C a b | a - b
   instance C Int Bool

   f :: forall a. C Int a = a - a
   f x = x

 GHC rejects the type signature for f, because we can see that 'a' *must
 be* Bool, so it's a bit misleading to universally quantify it.

Ok, maybe this is a reasonable choice. But why does the attached program work? 
ghci presents a unique type for the universal quantified function 'eight':

*Add :t eight
eight :: Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))

Best regards,
  Dirk


 Simon

 | -Original Message-
 | From: [EMAIL PROTECTED]

 [mailto:glasgow-haskell-users-

 | [EMAIL PROTECTED] On Behalf Of Dirk Reckmann
 | Sent: 21 July 2005 10:30
 | To: glasgow-haskell-users@haskell.org
 | Subject: Functional Dependencies
 |
 | Hello everybody!
 |
 | I wanted to have some fun with functional dependencies (see
 | http://www.cs.chalmers.se/~hallgren/Papers/wm01.html), and tried some
 | examples from this paper as well as some own experiments. The idea is

 to use

 | the type checker for computations by abuse of type classes with

 functional

 | dependencies.
 |
 | The example in the attached file is taken from the above paper. Due to

 the

 | functional dependencies, I expected the type of seven to be uniquely
 | determined to be (Succ (Succ (Succ ...))), i. e. seven, but ghc

 (version 6.4)

 | gives me following error message:
 |
 | Add.hs:14:0:
 | Couldn't match the rigid variable `a' against `Succ s'
 |   `a' is bound by the type signature for `seven'
 |   Expected type: Succ s
 |   Inferred type: a
 | When using functional dependencies to combine
 |   Add (Succ n) m (Succ s), arising from the instance declaration

 at

 | Add.hs:11:0
 |   Add (Succ (Succ (Succ Zero))) (Succ (Succ (Succ (Succ Zero

 a,

 | arising from the type signature for `seven' at Add.hs:13:0-77
 | When generalising the type(s) for `seven'
 |
 | However, using the definition of Add to define Fibonacci numbers does

 work,

 | and a similar function declaration can be used to compute numbers by

 the type

 | checker.
 |
 | The same definition of Add works in Hugs...
 |
 | So, is this a bug in ghc, or am I doing something wrong?
 |
 | Thanks in advance,
 | Dirk Reckmann
{-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-}

module Add where

data Zero
data Succ n

class Add n m s | n m - s

instance Add Zero m m
instance Add n m s = Add (Succ n) m (Succ s)

class Fib n f | n - f

instance Fib Zero (Succ Zero)
instance Fib (Succ Zero) (Succ Zero)
instance (Fib n fib_n,
  Fib (Succ n) fib_s_n,
  Add fib_n fib_s_n sum
 ) = Fib (Succ (Succ n)) sum

eight :: Fib (Succ (Succ (Succ (Succ (Succ Zero) n = n
eight = undefined
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


RE: Functional Dependencies

2005-08-11 Thread Simon Peyton-Jones
You raise a vexed question, which has been discussed a lot.  Should this
typecheck?

class C a b | a - b 
instance C Int Bool

f :: forall a. C Int a = a - a
f x = x

GHC rejects the type signature for f, because we can see that 'a' *must
be* Bool, so it's a bit misleading to universally quantify it.   

Simon

| -Original Message-
| From: [EMAIL PROTECTED]
[mailto:glasgow-haskell-users-
| [EMAIL PROTECTED] On Behalf Of Dirk Reckmann
| Sent: 21 July 2005 10:30
| To: glasgow-haskell-users@haskell.org
| Subject: Functional Dependencies
| 
| Hello everybody!
| 
| I wanted to have some fun with functional dependencies (see
| http://www.cs.chalmers.se/~hallgren/Papers/wm01.html), and tried some
| examples from this paper as well as some own experiments. The idea is
to use
| the type checker for computations by abuse of type classes with
functional
| dependencies.
| 
| The example in the attached file is taken from the above paper. Due to
the
| functional dependencies, I expected the type of seven to be uniquely
| determined to be (Succ (Succ (Succ ...))), i. e. seven, but ghc
(version 6.4)
| gives me following error message:
| 
| Add.hs:14:0:
| Couldn't match the rigid variable `a' against `Succ s'
|   `a' is bound by the type signature for `seven'
|   Expected type: Succ s
|   Inferred type: a
| When using functional dependencies to combine
|   Add (Succ n) m (Succ s), arising from the instance declaration
at
| Add.hs:11:0
|   Add (Succ (Succ (Succ Zero))) (Succ (Succ (Succ (Succ Zero
a,
| arising from the type signature for `seven' at Add.hs:13:0-77
| When generalising the type(s) for `seven'
| 
| However, using the definition of Add to define Fibonacci numbers does
work,
| and a similar function declaration can be used to compute numbers by
the type
| checker.
| 
| The same definition of Add works in Hugs...
| 
| So, is this a bug in ghc, or am I doing something wrong?
| 
| Thanks in advance,
|   Dirk Reckmann
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Functional dependencies, principal types, and decidable typechecking

2005-04-06 Thread Keean Schupke
Manuel M T Chakravarty wrote:
I accept that this is the process by which GHC computes these types, but
it does violate the principal types property, doesn't it?  The relation
 Int - ()   =   forall c. Int - c
does not hold.
 

I realise that principal types and principal typings are slightly 
different, but I was
wondering if the fact that it has recently been shown that 
Hindley/Milner does not
have principal typings has any meaning here?

Keean.
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Functional dependencies, principal types, and decidable type checking

2005-04-05 Thread Manuel M T Chakravarty
Iavor Diatchki wrote:
 Hi,
 
 On Apr 3, 2005 7:33 AM, Manuel M T Chakravarty [EMAIL PROTECTED] wrote:
  Assume the following type class declarations with functional
  dependencies:
  
   {-# OPTIONS -fglasgow-exts #-}
  
   class C a b c | a b - c where
foo :: (a, b) - c
  
   instance C a a r = C a (b, c) r where
 foo (a, (b, c)) = foo (a, a)
  
  Now, in GHCi (version 6.4),
  
   *FDs let bar x = foo ((x, x), (x, x))
   *FDs :t bar
   bar :: (C (a, a) (a, a) c) = a - c
 This seems reasonable.

It is reasonable in so far as it is a valid typing, but Haskell
(including FDs) comes with the promise of type inference determining
principal (as in most general) types.

  but GHC is also happy to accept the more general type
  
   bar :: a - c
   bar x = foo ((x, x), (x, x))

We know

  a - c   =   (C (a, a) (a, a) c) = a - c

where = is the is more or as general as relation, but due to GHCi's
answer to :t bar, it must also be true that

  (C (a, a) (a, a) c) = a - c   =   a - c

To check whether that relation holds, we need to know the set of
satisfiable instances of the predicate C (a, a) (a, a) c under the
given instance declaration.  It seems as if we get infinite inference
trees here.

 It seems that GHC 6.4 has a new feature where it is creating
 recursive dictionaries (which is sometimes useful).   Here is a
 simpler example of the same behavior:
  {-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-}
  
  class T a where t :: a
  instance T a = T a where t = t
  
  f :: Int
  f = t
 GHC accepts this which means that it managed to discharge the
 constraint T Int, and the only way it could have done this is by
 creating a recursive (in this case bottom) dicitionary.

Yes, *but* you have given GHC -fallow-undecidable-instances!!  My
examples doesn't require that.

   *FDs let bar x = foo ((x::Int, x), (x, x))
   *FDs :t bar
   bar :: Int - ()
 This looks like a bug to me.

This only happens when the functional dependency a b - c is used in
the class declaration.  I think what is happening is that the type
variable that was to the right of the error is zonked (in error) after
type checking.

 I think that if an implementation creates recursive dictionaries it
 may be nice to have some sort of a progress check to avoid creating
 completely undefined dictionaries.  I suspect implementing such a
 thing may be tricky though.

I am actually a bit worried about the type theory of this all.
Recursive dictionaries sounds like a cool idea, but what does it mean in
terms of typing derivations?  Moreover, how does that combine with
improving substitutions, such as those used in the implementation of
functional dependencies?

Manuel


___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


RE: Functional dependencies, principal types, and decidable typechecking

2005-04-05 Thread Simon Peyton-Jones
Manuel

Your short program tickles a lot of different questions.  Here's an
explanation.

Simon

| Assume the following type class declarations with functional
| dependencies:

Actually much of the behaviour you see happens without fundeps.
 
|  {-# OPTIONS -fglasgow-exts #-}
| 
|  class C a b c | a b - c where
|   foo :: (a, b) - c
| 
|  instance C a a r = C a (b, c) r where
|foo (a, (b, c)) = foo (a, a)

You are already on dodgy ground here, because the instance decl doesn't
guarantee that the bit before the = is smaller than the bit after the
=.  E.g. context reduction could go:
C (Int,Int) (Bool, Bool) r 
-- C (Int,Int) (Int,Int) r
-- C (Int,Int) (Int,Int) r

So [Point 1]: GHC should require -fallow-undecidable-instances if you
use repeated type variables before the =.


| Now, in GHCi (version 6.4),
| 
|  *FDs let bar x = foo ((x, x), (x, x))
|  *FDs :t bar
|  bar :: (C (a, a) (a, a) c) = a - c
| 
| but GHC is also happy to accept the more general type
| 
|  bar :: a - c
|  bar x = foo ((x, x), (x, x))

There are two separate things going on here

[Point 2]  GHC postpones context reduction until it's forced to do it
(except if a single step will eliminate the dictionary altogether).
Example:

data T a = T a
instance Eq (T a)
bar x = [T x] == []

GHC will *infer* bar :: Eq [T a] = a - Bool, but it will happily
*check*
bar :: a - Bool
bar x = [T x] == []

The reason for this lazy context reduction is overlapping instances; in
principle there might be more instances for Eq [T a] at bar's call site.

But now I look at it again, I think it would be OK to postpone context
reduction only if there actually were overlapping instances (right here
at bar's defn).  That might be a good idea because it'd give less
confusing types perhaps.

However, note that the two types are indeed equivalent -- both are more
general than the other.  It's like saying   (Eq Int = t)  =  t,
and vice versa.


[Point 3]  As Iavor notes, yes, GHC is building recursive dictionaries.
Suppose GHC is trying to find evidence for constraint C from a set of
constraints (with evidence provided) D.  Suppose it finds an instance
decl D' = C which matches C.  Then it tries to prove the constraints
D'.  The new bit is that it adds C to D before trying to prove D'.
That's all!

This is Jolly Useful sometimes.   (See John Hughes's paper about
restricted type synonyms for example.)   It's a bit like infinite data
structures.  ML doesn't let you build them, so there's a static error.
Haskell does, and that is sometimes just what you want; and sometimes
gives you runtime divergence (e.g. take the length of an infinite list).
In the same way, this recursive-dictionary thing is sometimes just what
you want; but sometimes gives you runtime divergence instead of a static
error.


| Again, in GHCi,
| 
|  *FDs let bar x = foo ((x::Int, x), (x, x))
|  *FDs :t bar
|  bar :: Int - ()
| 
| (which by itself is bizarre)

This is the first time when the functional dependency plays a role.
From bar's right-hand-side we get the constraint (C (Int,Int) (Int,Int)
c), and the type (Int - c).  Now GHC tries to decide what to quantify
over.  Shall we quantify over c?  Well, no.  GHC never quantifies over
type variables that are free in the environment (of course) OR are fixed
by functional dependencies from type variables free in the environment.
In this case the functional dependencies tell us that since (Int,Int) is
obviously completely fixed, then there's no point in quantifying over c.


So bar is not quantified.  The constraint (C (Int,Int) (Int,Int) c) is
satisfied via the recursive dictionary thing, leaving 'c' completely
unconstrained.  So GHC chooses c to be (), because it doesn't like to
leave programs with completely free type variables.

| but it also accepts
| 
|  bar :: Int - c
|  bar x = foo ((x::Int, x), (x, x))

Here you are *telling* GHC what to quantify over, so the inference of
what to quantify doesn't happen.


___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


RE: Functional dependencies, principal types, and decidable typechecking

2005-04-05 Thread Manuel M T Chakravarty
Simon Peyton-Jones wrote:

 |  {-# OPTIONS -fglasgow-exts #-}
 | 
 |  class C a b c | a b - c where
 |   foo :: (a, b) - c
 | 
 |  instance C a a r = C a (b, c) r where
 |foo (a, (b, c)) = foo (a, a)
 
 You are already on dodgy ground here, because the instance decl doesn't
 guarantee that the bit before the = is smaller than the bit after the
 =.  E.g. context reduction could go:
   C (Int,Int) (Bool, Bool) r 
 --   C (Int,Int) (Int,Int) r
 --   C (Int,Int) (Int,Int) r
 
 So [Point 1]: GHC should require -fallow-undecidable-instances if you
 use repeated type variables before the =.

Yes, I think that would be a good idea.

 | Now, in GHCi (version 6.4),
 | 
 |  *FDs let bar x = foo ((x, x), (x, x))
 |  *FDs :t bar
 |  bar :: (C (a, a) (a, a) c) = a - c
 | 
 | but GHC is also happy to accept the more general type
 | 
 |  bar :: a - c
 |  bar x = foo ((x, x), (x, x))
 
 There are two separate things going on here
 
 [Point 2]  GHC postpones context reduction until it's forced to do it
 (except if a single step will eliminate the dictionary altogether).
 Example:
 
   data T a = T a
   instance Eq (T a)
   bar x = [T x] == []
 
 GHC will *infer* bar :: Eq [T a] = a - Bool, but it will happily
 *check*
   bar :: a - Bool
   bar x = [T x] == []
 
 The reason for this lazy context reduction is overlapping instances; in
 principle there might be more instances for Eq [T a] at bar's call site.
 
 But now I look at it again, I think it would be OK to postpone context
 reduction only if there actually were overlapping instances (right here
 at bar's defn).  That might be a good idea because it'd give less
 confusing types perhaps.
 
 However, note that the two types are indeed equivalent -- both are more
 general than the other.  It's like saying (Eq Int = t)  =  t,
 and vice versa.

Semantically, I understand that the constraint C ((x, x), (x, x) a)
does not constrain the two type variables x and a (and hence, the
two types are equivalent), but I don't see how you can derive that with
the constraint entailment rules

  \theta \in P
  
  P ||- \theta

  P ||- forall a.\theta
  -
  P || [t/a]\theta 

  P || p = \phi   P ||- p
  
   P ||- \phi

which I thought are those underlying GHC's type system.

 | Again, in GHCi,
 | 
 |  *FDs let bar x = foo ((x::Int, x), (x, x))
 |  *FDs :t bar
 |  bar :: Int - ()
 | 
 | (which by itself is bizarre)
 
 This is the first time when the functional dependency plays a role.
 From bar's right-hand-side we get the constraint (C (Int,Int) (Int,Int)
 c), and the type (Int - c).  Now GHC tries to decide what to quantify
 over.  Shall we quantify over c?  Well, no.  GHC never quantifies over
 type variables that are free in the environment (of course) OR are fixed
 by functional dependencies from type variables free in the environment.
 In this case the functional dependencies tell us that since (Int,Int) is
 obviously completely fixed, then there's no point in quantifying over c.
 
 
 So bar is not quantified.  The constraint (C (Int,Int) (Int,Int) c) is
 satisfied via the recursive dictionary thing, leaving 'c' completely
 unconstrained.  So GHC chooses c to be (), because it doesn't like to
 leave programs with completely free type variables.
 
 | but it also accepts
 | 
 |  bar :: Int - c
 |  bar x = foo ((x::Int, x), (x, x))
 
 Here you are *telling* GHC what to quantify over, so the inference of
 what to quantify doesn't happen.

I accept that this is the process by which GHC computes these types, but
it does violate the principal types property, doesn't it?  The relation

  Int - ()   =   forall c. Int - c

does not hold.

Summary
~~~
So it seems to me that

* MPTCs with recursive dictionary construction seem to require a
semantic model of subsumption (as the normal constraint entailment rules
would lead to infinite trees).

* MPTCs with recursive dictionary construction and FDs break principal
types.

I guess that's all ok provided GHC enforces the use of
-fallow-undecidable-instances for any instances that need recursive
dictionaries. 

Manuel


___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


Re: Functional dependencies, principal types, and decidable type checking

2005-04-03 Thread Iavor Diatchki
Hi,

On Apr 3, 2005 7:33 AM, Manuel M T Chakravarty [EMAIL PROTECTED] wrote:
 Assume the following type class declarations with functional
 dependencies:
 
  {-# OPTIONS -fglasgow-exts #-}
 
  class C a b c | a b - c where
   foo :: (a, b) - c
 
  instance C a a r = C a (b, c) r where
foo (a, (b, c)) = foo (a, a)
 
 Now, in GHCi (version 6.4),
 
  *FDs let bar x = foo ((x, x), (x, x))
  *FDs :t bar
  bar :: (C (a, a) (a, a) c) = a - c
This seems reasonable.


 but GHC is also happy to accept the more general type
 
  bar :: a - c
  bar x = foo ((x, x), (x, x))

It seems that GHC 6.4 has a new feature where it is creating
recursive dictionaries (which is sometimes useful).   Here is a
simpler example of the same behavior:
 {-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-}
 
 class T a where t :: a
 instance T a = T a where t = t
 
 f :: Int
 f = t
GHC accepts this which means that it managed to discharge the
constraint T Int, and the only way it could have done this is by
creating a recursive (in this case bottom) dicitionary.

  *FDs let bar x = foo ((x::Int, x), (x, x))
  *FDs :t bar
  bar :: Int - ()
This looks like a bug to me.

 For those who expected GHC to diverge during type checking with the
 above class declaration, console yourself by knowing that Hugs (Feb'05)
 does diverge...well, it invokes the emergency break:

I think this is what GHC used to do, and indeed seems quite
reasonable.  I guess one could be more lazy in the context reduction
(like GHC did in the first example), and only diverge if the function
is actually used.

I think that if an implementation creates recursive dictionaries it
may be nice to have some sort of a progress check to avoid creating
completely undefined dictionaries.  I suspect implementing such a
thing may be tricky though.

-Iavor
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


[Haskell] Re: Functional dependencies interfere with generalization

2004-01-28 Thread oleg

I'm sorry to open an old wound. I've just had an insight for
a clarification.

On Nov 26, 2003 Ken Shan wrote:

 Consider the following code, which uses type classes with functional
 dependencies:

 {-# OPTIONS -fglasgow-exts #-}
 module Foo where
 class R a b | a - b where r :: a - b

 -- 1
 rr :: (R a b1, R a b2) = a - (b1, b2)
 rr a = (r a, r a)

 -- 2
 data RAB a = RAB (forall b. (R a b) = (a, b))
 mkRAB :: (R a b) = a - b - RAB a
 mkRAB a b = RAB (a, b)

 Neither 1 nor 2 passes the type-checker (GHC 6.0.1).  The error messages
 are similar:
 Inferred type is less polymorphic than expected
 Quantified type variable `b2' is unified with another
 quantified type variable
 When trying to generalise the type inferred for `rr'
 Signature type: forall a b1 b2.
 (R a b1, R a b2) =
 a - (b1, b2)
 Type to generalise: a - (b1, b1)

 In both cases, the compiler is failing to make use of functional
 dependencies information that it has at its disposal.  Specifically,
 it seems to me that, if two type variables b1 and b2 have been unified
 due to functional dependencies, making two constraints in the context
 identical, then the inner constraint (inner with respect to the scope
 of quantified type variables) should be ignored.

Regarding the function rr, I'm afraid I'm compelled to side with the
typechecker. It appears that the typechecker does make use of the
functional dependencies to reject the code because the user has
specified too general a signature. Exactly the _same_ error occurs in
the following code

ab:: a - Maybe a
ab = Just

rrr:: a - (Maybe a, Maybe a1)
rrr a = (ab a, ab a)

Inferred type is less polymorphic than expected
Quantified type variable `a1' is unified with another
quantified type variable `a'
When trying to generalise the type inferred for `rrr'
Signature type: forall a a1. a - (Maybe a, Maybe a1)
Type to generalise: a1 - (Maybe a1, Maybe a1)
When checking the type signature for `rrr'
When generalising the type(s) for `rrr'

Error messages are identical.

Because ab is a function rather than a method, there trivially is a
functional dependency between the function's argument and its result.

Furthermore, exactly the same error occurs in

:: a - b
 x = x

Inferred type is less polymorphic than expected
Quantified type variable `b' is unified with
another quantified type variable `a'
When trying to generalise the type inferred for `'
Signature type: forall a b. a - b
Type to generalise: b - b
When checking the type signature for `'
When generalising the type(s) for `'


Regarding the original function rr, the best solution seems to be to
let the compiler figure out its type. It seems in these circumstances
the most general type exists -- and thus the compiler can figure it
out.

Now, regarding function mkRAB. It seems there is a simple solution:

data RAB a = RAB (forall b. (R a b) = (a, b))
mkRAB a = RAB (a, r a)

Indeed, the class R a b promised that there is a function 'r' such
that given a value of type 'a' can produce a value of type 'b'. So, we
can make use of such a function.

One can object: in a value of a type RAB (forall b. (R a b) = (a, b)),
the types of two components of a pair `(a, b)' must be related by the
relation R a b. The values can in principle be arbitrary. What if one
wishes to create a value RAB (x,z) such that the value z has the type of
(r x) but is not equal to (r x)? Well, there is an underhanded way to
help that.

class R a b | a - b where 
   r ::  a - b
   r1 :: a - Integer - b

that is, we define an additional method that takes an integer and
somehow makes the value of a type 'b'. We may imagine an Array(s) of all
possible values of type 'b' (specialized for those types 'b' for which
there are instances of the class R) and the method r1 merely uses its
second argument to select from that array. In any case, Goedel showed
that quite many pleasant and unpleasant things can be encoded in
integers. The first argument of r1 is merely a window dressing to
make the typechecker happy.

Thus we can define

mkRAB' a b = RAB (a, r1 a b)

To make the code more concrete, we introduce two instances

instance R Int Char where {r = toEnum; r1 _ = toEnum . fromInteger}
instance R Float (Maybe Float) where
r = Just
r1 _ 1 = Nothing
r1 _ n = Just (fromRational $ toRational (n-1) / (2^(128+1)))


In the second instances, we take advantage of the existence of an
injection from IEEE floating-point numbers to integers.

We can try evaluating mkRAB 65, mkRAB' 65 66, mkRAB' (1.0::Float)
0, etc. -- and everything works.

Building RAB values is not enough -- we should be able to use
them. For example, we should be 

Re: Functional dependencies interfere with generalization

2003-11-27 Thread Brandon Michael Moore


On Wed, 26 Nov 2003, Ken Shan wrote:

 Hello,

 Consider the following code, which uses type classes with functional
 dependencies:

 {-# OPTIONS -fglasgow-exts #-}
 module Foo where
 class R a b | a - b where r :: a - b

 -- 1
 rr :: (R a b1, R a b2) = a - (b1, b2)
 rr a = (r a, r a)

 -- 2
 data RAB a = RAB (forall b. (R a b) = (a, b))
 mkRAB :: (R a b) = a - b - RAB a
 mkRAB a b = RAB (a, b)

 Neither 1 nor 2 passes the type-checker (GHC 6.0.1).  The error messages
 are similar:

I agree that the typechecker could handle this better, but I don't see why
you should need types like this. You should be able to use

rr :: (R a b) =  a - (b,b)

and

data RAB a = forall b. (R a b) = RAB (a,b)

equally well, and these typecheck.

I think the root of the problem is the foralls. The typechecker doesn't
realize that there is only one possible choice for thse universally
quantified values based on the functional dependencies. For rr it
complains because you can't allow every b2, just b2 = b1, not realizing
that that is already implied by the class constraints. Similarly for RAB
it complains because the pair you give it is obviously not unviersally
polymorphic in b, not realizing that there is only one choice for b
consistent with the class constraints. Compare this code:

class R a b where r :: a - b

rr :: (R a b1, R a b2) = a - (b1, b2)
rr x = let rx = r x in (rx, rx)

and

data P a = P (forall b. (a,b))

Off the top of a my head, the solution to this problem would probably be
something like ignoring foralls on a type variable that is determined by
fundeps, but I think the type system would need some sort of new
quantifier or binding construct to introduce a new type variable that is
completely determined by its class constraints. Something like forall a .
constrained b. (R a b) = a - (b, b). A forall binding a variable
determined by fundeps could be reduced to a constrained binding, which
would be allowed to do things like unify with other type variables.

I'm not sure anything really needs to be done. I think you can always
type these examples by unifying the reduntant type variables in a
signature by hand, and by using existentially quantified data types
rather than universally quantified ones. Do you have examples that
can't be fixed like this?

Brandon



 Inferred type is less polymorphic than expected
 Quantified type variable `b2' is unified with another quantified type 
 variable `b1'
 When trying to generalise the type inferred for `rr'
 Signature type: forall a b1 b2.
 (R a b1, R a b2) =
 a - (b1, b2)
 Type to generalise: a - (b1, b1)
 When checking the type signature for `rr'
 When generalising the type(s) for `rr'

 Inferred type is less polymorphic than expected
 Quantified type variable `b' escapes
 It is mentioned in the environment:
   b :: b (bound at Foo.hs:17)
 In the first argument of `RAB', namely `(a, b)'
 In the definition of `mkRAB': mkRAB a b = RAB (a, b)

 In both cases, the compiler is failing to make use of functional
 dependencies information that it has at its disposal.  Specifically,
 it seems to me that, if two type variables b1 and b2 have been unified
 due to functional dependencies, making two constraints in the context
 identical, then the inner constraint (inner with respect to the scope
 of quantified type variables) should be ignored.

 Is there a technical reason why the type checker should reject the code
 above?  Would it be possible to at least automatically define a function
 like

 equal :: forall f a b1 b1. (R a b1, R a b2) = f b1 - f b2

 for every functional dependency, with which I would be able to persuade
 the type checker to generalize (Baars and Swierstra, ICFP 2002)?  I
 suppose I can use unsafeCoerce to manually define such a function... is
 that a bad idea for some reason I don't see?

 Thank you,
   Ken

 --
 Edit this signature at http://www.digitas.harvard.edu/cgi-bin/ken/sig
 Tax the rich!
 new journal Physical Biology: http://physbio.iop.org/
 What if All Chemists Went on Strike? (science fiction):
 http://www.iupac.org/publications/ci/2003/2506/iw3_letters.html


___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


Re: Functional dependencies interfere with generalization

2003-11-27 Thread Ken Shan
On 2003-11-27T07:51:37-0800, Brandon Michael Moore wrote:
 I agree that the typechecker could handle this better, but I don't see why
 you should need types like this. You should be able to use
 
 rr :: (R a b) =  a - (b,b)
 
 and
 
 data RAB a = forall b. (R a b) = RAB (a,b)
 
 equally well, and these typecheck.

 [...]

 I'm not sure anything really needs to be done. I think you can always
 type these examples by unifying the reduntant type variables in a
 signature by hand, and by using existentially quantified data types
 rather than universally quantified ones. Do you have examples that
 can't be fixed like this?

Thanks for indicating that I am not out of my mind!  Unfortunately,
when I try to use an existential type for RAB as you do above, I run
into problems later when unpacking the value.  Essentially, I need the
type system to be smart at either universal introduction or existential
elimination.  For example, I can't write:

useRAB :: (Eq b, R a b) = RAB a - b - Bool
useRAB (RAB (a, b1)) b2 = b1 == b2

The compiler makes two complaints:

Could not deduce (Eq b) from the context (R a b)
  arising from use of `=='
Probable fix:
Add (Eq b) to the existential context of a data constructor
In the definition of `useRAB': useRAB (RAB (a, b1)) b2 = b1 == b2

Inferred type is less polymorphic than expected
Quantified type variable `b' escapes
When checking an existential match that binds
b1 :: b
and whose type is RAB a - b1 - Bool
In the definition of `useRAB': useRAB (RAB (a, b1)) b2 = b1 == b2

The first complaint is that it doesn't know that the b from within the
RAB is an instance of Eq.  The second complaint is that it doesn't
know that the b from within the RAB is the same as the one from
outside.

The first complaint seems to be due to failing to infer Eq b1 from

Eq b, R a b, R a b1.

This seems to me like a matter of simply unifying b with b1, but perhaps
I am missing something.  As for the second complaint:

 I think the root of the problem is the foralls. [...]

Right...

 Off the top of a my head, the solution to this problem would probably be
 something like ignoring foralls on a type variable that is determined by
 fundeps, but I think the type system would need some sort of new
 quantifier or binding construct to introduce a new type variable that is
 completely determined by its class constraints. Something like forall a .
 constrained b. (R a b) = a - (b, b). A forall binding a variable
 determined by fundeps could be reduced to a constrained binding, which
 would be allowed to do things like unify with other type variables.

Looking at section 6.4 (generalizing inferred types) of Mark Jones's
ESOP 2000 paper (http://www.cse.ogi.edu/~mpj/pubs/fundeps.html), I have
another possible solution that doesn't involve a new kind of quantifier
or binding construct.  Jones says that

In a standard Hindley-Milner type system, principal types are
computed using a process of generalization.  Given an inferred
but unquantified type P=t, we would normally just calculate the
set of type variables T = TV(P=t), over which we might want to
quantify, and the set of variables V = TV(A) that are fixed in the
current assumptions A, and then quantify over any variables in
the difference, T\V.  In the presence of functional dependencies,
however, we must be a little more careful: a variable a that appears
in T but not in V may still need to be treated as a fixed variable
if it is determined by V.  To account for this, we should only
quantify over the variables in T\V+.

(Here V+ is the set of all type variables uniquely determined by the
type variables in V via functional dependencies.)  Contrary to this
paragraph, I think we can actually be -less- careful in the presence
of functional dependencies: we can quantify over any variable v in T,
even if v also appears in V, as long as v is determined by V\{v} via
functional dependencies, by renaming v to some fresh v'.

Unfortunately, this procedure must be guided by type annotations if it
is to work deterministically (i.e., giving rise to principal types).
For example:

class Q a c | a - c
class R b c | b - c

data QAC a = QAC (forall c. (Q a c) = (a, c))
data RBC b = RBC (forall c. (R b c) = (b, c))

mk2 :: (Q a c, R b c) = a - b - c - (QAC a, RBC b)
mk2 a b c = (QAC (a, c), RBC (b, c))
-- or equivalently --
mk2 a b c = let c' = c in (QAC (a, c'), RBC (b, c'))

Here the type of c aka c' needs to be generalized to

forall c'. (Q a c') = c'

on one hand, and

forall c'. (R b c') = c'

on the other.  Both type-schemes are valid semantically, but they are
not comparable -- neither subsumes the other.  I would be quite content
with a type-checker that uses local type inference (in this case, the
definition of QAC and RBC) to decide how to generalize.

I've also just discovered Simplifying and Improving Qualified Types

RE: Functional dependencies and Constructor Classes

2002-11-20 Thread Martin Sulzmann
Mark P Jones writes:
  | The issue I want to raise is whether constructor classes are 
  | redundant in the presence of FDs
  
  No, they are not comparable.
  
Allow me to make the following bold claim.

Assume we are given a program that uses the Haskell functor class as in

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

We translate such a program by using

class Fmap a b fa fb | a fb - b fa, 
   b fa - a fb,
   fa fb - a b 
where fmap :: (a-b)-(fa - fb) 

instead. Instances are translated in the obvious way.
Then, if the original program is typable, so will be the translated
program, meaning is preserved.

  Your fds version of the Functor class is also incomparable with the
  ccs version; the former will allow an expression like (map id 'a')

Yes, because FD's are not expressive enough to specify the form
of improvement we need.

Consider

module Fmap where

class Fmap a b fa fb | a fb - b fa, 
   b fa - a fb,
   fa fb - a b 
where fmap2 :: (a-b)-(fa - fb)


-- identity functor
instance Fmap a a a a where fmap2 h = h

e = fmap2 id 'a'

yields

Type checking  
ERROR Fmap2.hs:17 - Unresolved top-level overloading
*** Binding : e
*** Outstanding context : Fmap c c Char b

though we would like to improve this type

to Fmap Char Char Char Char  where

c=Char and b=Char

  I believe the same is true in this case.  Ccs and fds address
  different problems.  They are complementary tools, each with their
  own strengths and weaknesses.
  

I believe that a refined form of fds is able to encode Ccs.
Give me some time to provide more evidence for my unsupported claims.

Martin


___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell



Re: Functional dependencies and Constructor Classes

2002-11-19 Thread Yoann Padioleau
Martin Sulzmann [EMAIL PROTECTED] writes:

 Yoann Padioleau writes:
   nevertheless i found constructor class more elegant for many problems.
   Your solution is less elegant that the one using constructor classes.
   
 
 Yes, the current presentation of constructor classes might be easier
 to comprehend.
 
   I found too that type error messages of class using functionnal depedencies 
   are not easy to read. There is often ambiguity in code that are not easy to 
solver.
   this problem does not appear with constructor classes.
   
 
 Well, that's the point of my encoding of functors using FD's. No
 ambiguities will arise!
 
 The issue I want to raise is whether constructor classes are redundant
 in the presence of FDs (yes, yes, we still might want to stick to the
 constructor class representation, but that's a different issue).

Oh, sorry, i misinterpret what you wanted to say.


 
 Martin
 
 
 

-- 
  Yoann  Padioleau,  INSA de Rennes, France,
Opinions expressed here are only mine. Je n'écris qu'à titre personnel.
**   Get Free. Be Smart.  Simply use Linux and Free Software.   **
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell



Re: Functional dependencies and Constructor Classes

2002-11-18 Thread Yoann Padioleau
Martin Sulzmann [EMAIL PROTECTED] writes:

 Hi,
 
 I was wondering whether other people made similiar observations.
 Functional dependencies seem to be expressiveness enough to encode
 some of the kinding rules required for Constructor Classes.

read this page: 
 http://cvs.haskell.org/Hugs/pages/hugsman/exts.html
I think that the designer of constructor class and functionnal depedencies is the same
person si it makes sense that one generalise the other.

nevertheless i found constructor class more elegant for many problems.
Your solution is less elegant that the one using constructor classes.

I found too that type error messages of class using functionnal depedencies 
are not easy to read. There is often ambiguity in code that are not easy to solver.
this problem does not appear with constructor classes.




 
 Take a look at the Haskell code below
 (runs under hugs -98 or  ghci -fglasgow-exts-fallow-undecidable-instances)
 
 Martin
 
 
 
 -- An alternative to constructor classes
 
 module Fmap where
 
 {- Instead of
 class Functor f where fmap :: (a-b)-(f a-f b)
 
 use
 -}
 
 class Fmap a b fa fb | a fb - b fa, 
b fa - a fb,
fa fb - a b 
 where fmap2 :: (a-b)-(fa - fb)
 
 {- We require:
 
 (1) fmap2 transforms a function into another function,
 i.e. fmap2's type should always be of shape (a-b)-(fa-fb)
 
 (2) b, fa uniquely determine a and fb
 
 (3) a, fb   b and fa
 
 (4) fa, fb  a and b
 
 Note that (1) is enforced by the class definition. (2)-(4) are enforced by FDs.
 
 My guess/conjecture is that the above axiomatization of functors is equivalent to the
 one found in Haskell98.
 -}
 
 -- some Examples
 
 {- The following is a variation of an example taken from Mark Jones original paper 
 A System of Constructor Classes: Overloading and Implicit Higher-Order 
Polymorphism.
 He used this example to motivate the introduction of constructor classes. The example
 is type correct using the alternative formulation of functors.
 -}
 
 cmap :: (Fmap a b fb1 fb, Fmap a1 b1 fa fb1) =
  (a1 - b1) - (a - b) - fa - fb
 cmap f g = (fmap2 g) . (fmap2 f)
 
 
 -- identity functor
 instance Fmap a a a a where fmap2 h = h
 
 -- functor composition 
 -- Instance is not allowed, cause leads to undecidable type inference
 
 {-
 instance (Fmap a b c d, Fmap e f a b) = Fmap e f c d
where fmap2 h = fmap2 (fmap2 h)
 -}
 
 comp :: (Fmap fa1 fb1 fa fb, Fmap a b fa1 fb1) =
  (a - b) - fa - fb
 comp h = fmap2 (fmap2 h)
 
 
 
 ___
 Haskell mailing list
 [EMAIL PROTECTED]
 http://www.haskell.org/mailman/listinfo/haskell
 

-- 
  Yoann  Padioleau,  INSA de Rennes, France,
Opinions expressed here are only mine. Je n'écris qu'à titre personnel.
**   Get Free. Be Smart.  Simply use Linux and Free Software.   **
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell



Re: Functional dependencies and Constructor Classes

2002-11-18 Thread Martin Sulzmann
Yoann Padioleau writes:
  nevertheless i found constructor class more elegant for many problems.
  Your solution is less elegant that the one using constructor classes.
  

Yes, the current presentation of constructor classes might be easier
to comprehend.

  I found too that type error messages of class using functionnal depedencies 
  are not easy to read. There is often ambiguity in code that are not easy to solver.
  this problem does not appear with constructor classes.
  

Well, that's the point of my encoding of functors using FD's. No
ambiguities will arise!

The issue I want to raise is whether constructor classes are redundant
in the presence of FDs (yes, yes, we still might want to stick to the
constructor class representation, but that's a different issue).

Martin


___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell



RE: Functional dependencies and Constructor Classes

2002-11-18 Thread Mark P Jones
Hi Martin,

| The issue I want to raise is whether constructor classes are 
| redundant in the presence of FDs

No, they are not comparable.

Let fds = functional dependencies
ccs = constructor classes

Example of something you can do with ccs but not fds:

   data Fix f = In (f (Fix f))

Example of something you can do with fds but not ccs:

   class Collects e ce where ...   -- see fds paper for details
   instance Eq e = Collects e [e] where ...
   instance Eq e = Collects e (e - Bool) where ...

Your fds version of the Functor class is also incomparable with the
ccs version; the former will allow an expression like (map id 'a')
to be type checked, the latter will not, treating it instead as a
type error.  In this specific case you may regard the extra flexibility
provided by fds as a win for expressiveness.  On another occasion,
however, you may be disappointed to discover that you have delayed
the detection of a type error from the point where it was introduced.

There's a lot more that could be said about this, but I don't have
time to go into detail now.  Hopefully, I have at least answered your
basic question.  The approach you've suggested using fds reminds me
most directly of the work on Parametric Type Classes (PTC) by Chen,
Hudak and Odersky.  In my paper on Functional dependencies, I made
the following comment regarding that work:

 Thus, PTC provides exactly the tools that we need to define and
  work with a library of collection classes.  In our opinion, the
  original work on PTC has not received the attention that it
  deserves. In part, this may be because it was seen, incorrectly,
  as an alternative to constructor classes and not, more accurately,
  as an orthogonal extension.

I believe the same is true in this case.  Ccs and fds address
different problems.  They are complementary tools, each with their
own strengths and weaknesses.

All the best,
Mark

Refs: for those who want to follow along:

  Type Classes with Functional Dependencies
http://www.cse.ogi.edu/~mpj/pubs/fundeps.html

  Constructor Classes
http://www.cse.ogi.edu/~mpj/pubs/fpca93.html
(But read the JFP version instead if you can; it's
much better ...)

___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell



RE: functional dependencies

2002-07-23 Thread Simon Peyton-Jones

I'm just catching up with some old mail here.

Iavor writes:

| class C a b | a - b
| class C a b = D a
| 
| vs.
| 
| class C a b | a - b
| class C a b = D a b
| 
| Hugs accepts both of those, while GHC insists on the second.  
| The first example is a little shorter and one might argue that if we 
| know a we also know b, because of the functional depency, 
| so it is not really a parameter.
|
| On the other hand, i would expect writing b in the type 
| signatures of any of the methods to refer to the particular b 
| determined by the a, rather than it becomeing universally
| quantified, and perhaps this is more explicit in the second form.  

Dead right!  Imagine there was a method in class D:

class C a b = D a where
   op :: a - b

The type of 'op' is

op :: D a = a - b

You can't really expect that the 'b' here is determined by 'a'!

Still, I suppose that if the methods in class D mention 
only 'a', then it is strange to require D to be parameterised over
'b'.  Thus, this seems more reasonable:

class C a b = D a where
  op :: a - a

Even this seems odd, because we would get the deduction

D a |- C a b

(i.e. from a (D a) dictionary you can get a (C a b) dictionary)
and that's only true for a particular 'b'.  My brain is too small
to be sure what I'm talking about here, but I'm strongly inclined
to be conservative here, which GHC is.

Simon
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell



RE: functional dependencies - bug?

2002-07-01 Thread Simon Peyton-Jones

Christian

This is clearly a bug in 5.03.  

However, it works fine in the (about to be released) 5.04. 
My plan, therefore, is to add it to our regression test suite
and delcare victory.   If I was being totally thorough I'd find
out what went wrong in 5.03, in case it's still wrong in 5.04, but
I'm not going to be totally thorough!

Please yell if any similar mysterious things happen.  I appreciate
the report.

Simon


| -Original Message-
| From: Christian Maeder [mailto:[EMAIL PROTECTED]] 
| Sent: 28 June 2002 18:09
| To: [EMAIL PROTECTED]
| Subject: functional dependencies - bug?
| 
| 
| Hi,
| 
| does anybody have experiences with Type Classes with 
| Functional Dependencies (LNCS 1782, ESOP 2000, March 200, by 
| Mark P. Jones)?
| 
| I've tried the example in the above paper:
| 
| class Collects e ce | ce - e where
| empty :: ce
| insert :: e - ce - ce
| member :: e - ce - Bool
| 
| This works correctly for:
| 
| instance Eq a = Collects a [a] where
| instance Collects Char Int where
| 
| and complains correctly for: 
| 
| instance Collects Char Int where
| instance Collects Bool Int where 
| 
| with Functional dependencies conflict between instance declarations
| 
| Now to my problem with a context in the class declaration:
| 
| class Eq ce = Collects e ce | ce - e where
| empty :: ce
| ...
| 
| This works as above, but correctly complains for:
| 
| data Stupid = Stupid -- without equality
| instance Collects Bool Stupid where
| 
| with No instance for (Eq Stupid).
| 
| However, if I supply an (admittingly stupid) default 
| definition for empty within the class declaration:
| 
| class Eq ce = Collects e ce | ce - e where
| empty :: ce
| empty = error(empty)
| ...
| 
| I no longer get the above No instance for (Eq 
| Stupid)-Message, and I guess that is a bug (or a feature 
| that I don't understand).
| 
| When I change the context to Eq e everything is fine again:
| 
| instance Collects Stupid Int where
| 
| complains as above.
| 
| I don't know when (even meaningful) default definitions cause 
| that context conditions are not checked. In fact I noticed 
| this error only after I've removed a default definition just 
| to find out that my instance declaration were wrong that 
| seemed to be correct before (but instances for contexts were missing).
| 
| Are there any other (known) pitfalls with functional dependencies?
| 
| Regards Christian ___
| Glasgow-haskell-users mailing list 
| [EMAIL PROTECTED] 
| http://www.haskell.org/mailman/listinfo/glasgow-| haskell-users
| 
___
Glasgow-haskell-users mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users



Re: Functional dependencies

2000-01-30 Thread Jeffrey R. Lewis

Marcin 'Qrczak' Kowalczyk wrote:

 Thank you for ghc-4.06!

 The following code is accepted by Hugs, but ghc complains about type
 variable r being not in scope. Adding "forall m r." causes the error
 "each forall'd type variable mentioned by the constraint must appear
 after the =", where Hugs still accepts it. If I understand functional
 dependencies, they should be legal. With a concrete monad fundeps work.

 class Reference r m | m - r where
 new :: a - m (r a)
 put :: r a - a - m ()
 get :: r a - m a

 test:: (Monad m, Reference r m) = m Int
 test = do
 x - new 42
 get x

Functional dependencies fall under the category of "Not-quite-ready-yet, but
in there nontheless".  But thanks for the report.  Functional dependencies and
implicit params won't be fully supported 'till a later release (hopefully the
next one).

--Jeff




RE: Functional Dependencies

1999-09-14 Thread Mark P Jones

Hi Fermin,

| Should redundant dependencies trigger an error or a warning? I'd 
| say that if I'm writing some haskell code, I wouldn't mind if a
| redundancy is flagged as an error; most likely, it'd take a short
| time to fix. However, if someone is generating haskell automatically
| (maybe with Derive, PolyP, a GUI designer, ...), the easiest thing
| to do is to generate all the dependencies that will make the types
| correct, without trying to avoid redundancies. In this case,
| I think a warning is better.

Generating a warning instead of an error might indeed be
preferable.  But I disagree with your motivation.  Except in
cases where a language is specifically designed to be used as
a target such programs, I believe that implementations should
be optimized for the benefit of their human users.  For the
comparatively rare cases where someone is writing a program
that generates Haskell class definitions, including dependencies,
it surely isn't too much to expect them to add a line or two to
filter out any that are redundant?  After all, they are probably
having to work much harder just to pretty print the rest of the
text.

A better solution still would be to have a standardized library
called HaskellSyntax, which all of the code generating tools that
you describe (and more!) could use.  The module would export a
set of datatypes for describing the abstract syntax of Haskell
programs and an associated set of pretty printers.  (Or perhaps
the printer functions by themselves would be enough?)  The pretty
printers would take care of all those minor little issues like
deciding when parentheses were needed, when an operator should
be written with applicative or infix syntax, breaking long strings
across line boundaries, etc.  It could also take care of filtering
out redundant dependencies, for example, if this was considered
useful.  I think this would be a neat library to have around,
especially if the authors of tools like Derive, PolyP, H/Direct,
Happy, or anything else that generates Haskell code could be
persuaded to use it.  I hope somebody will take up the challenge!

All the best,
Mark






Re: Functional Dependencies

1999-09-14 Thread Ross Paterson

Mark P Jones wrote:
| | Neat.  And it solves a problem I was kludging around with explicit,
| | existentially quantified dictionaries.
| 
| Great!  Can I look forward to hearing more about that some time?

OK, it's to do with arrows:

 class Arrow a where
   arr :: (b - c) - a b c
   () :: a b c - a c d - a b d
   first :: a b c - a (b,d) (c,d)

Given an arrow a, I want to form a new arrow

 newtype Instance f a b c = Inst (a (f b) (f c))

Defining arr and  is easy (provided f is a functor and a an arrow),
but to define first, we need an isomorphism between f(b,c) and (f b,g b)
for some functor g.  Some examples:

f   g

(,) s   Id  state transformers
Stream  Stream  synchronous circuits
(-) s  (-) s  a version of Dick Kieburtz's co-state comonad

With functional dependencies, I can presumably write

  class (Functor f, Functor g) = Zippable f g | f - g where
unzipper :: f(b,c) - (f b, g c)
zipper :: (f b, g c) - f(b,c)

  instance Zippable ((-) s) ((-) s) where
unzipper f = (fst . f, snd . f)
zipper (f,g) x = (f x, g x)

  instance (Zippable f g, Arrow a) = Arrow (Instance f a) where
arr f = Inst (arr (fmap f))
Inst f  Inst g = Inst (f  g)
first (Inst f) = Inst (arr unzipper  first f  arr zipper)

The type constructor g only features inside the last composition;
none of the top-level things have types that mention g, so doing this
without dependencies isn't easy.

The kludge I used was an explicit dictionary

 data ZipD f =
   forall g. ZipD
   (forall b,c. f(b,c) - (f b, g c))
   (forall b,c. (f b, g c) - f(b,c))

and a class

 class Functor f = Zippable f where
   zipD :: ZipD f

Defining an instance looked like this:

 instance Zippable ((-) s) where
   zipD = ZipD unzipper zipper
   where   unzipper f = (fst . f, snd . f)
   zipper (f,g) x = (f x, g x)

Then I could define the arrow:

 instance (Zippable f, Arrow a) = Arrow (Instance f a) where
   arr f = Inst (arr (fmap f))
   Inst f  Inst g = Inst (f  g)
   first (Inst f) = Inst (arr unzipper  first f  arr zipper)
   where   ZipD unzipper zipper = zipD

This kludge only handles situations where a subset of the arguments are
dependent on the rest.





Re: Functional Dependencies

1999-09-13 Thread Ross Paterson

Mark P Jones wrote:
 A couple of months ago, I developed and implemented an extension to
 Hugs that has the potential to make multiple parameter type classes
 more useful.  The key idea is to allow class declarations to be
 annoted with `functional dependencies'---an idea that has previously
 received rather more attention in the theory of relational databases.

Neat.  And it solves a problem I was kludging around with explicit,
existentially quantified dictionaries.

On a superficial note, how about
class C a b c | (a,b) = c where ...
for
class C a b c | a b - c where ...
etc?

Also, you say a dependency with zero variables on the right side is
syntactically correct, but later you say it will be reported as an
error because it says nothing.  Why bother?

-- Ross Paterson





RE: Functional Dependencies

1999-09-13 Thread Fermin Reig Galilea

 
 | Also, you say a dependency with zero variables on the right side is
 | syntactically correct, but later you say it will be reported as an
 | error because it says nothing.  Why bother?
 
 Point taken.  In fact that same database text I mentioned above
 prohibits functional dependencies in which either side is empty.
 But it turns out that the two extremes ("a -" and "- a") are
 rather interesting so I didn't want to exclude either as being
 syntactically well-formed.  Rejecting the former at a later stage
 was a design decision, intended only to catch errors, and isn't
 an essential part of the design.
 
 All the best,
 Mark

Should redundant dependencies trigger an error or a warning? I'd say that if
I'm writing some haskell code, I wouldn't mind if a redundancy is flagged as
an error; most likely, it'd take a short time to fix. However, if someone is
generating haskell automatically (maybe with Derive, PolyP, a GUI designer,
...), the easiest thing to do is to generate all the dependencies that will
make the types correct, without trying to avoid redundancies. In this case,
I think a warning is better. 

Just my 2 cents. 

Fermin







Re: Functional Dependencies

1999-09-12 Thread Heribert Schuetz

Hi Mark,

at the end of section 2 of http://www.cse.ogi.edu/~mpj/fds.html you
might want to mention that there is a "standard" work-around whenever a
type constructor is needed but not available: Introduce a newtype.

 import Bits

 class Collects e c where
empty  :: c e
insert :: e - c e - c e
member :: e - c e - Bool

 instance Eq e = Collects e [] where
   empty  = []
   insert = (:)
   member = elem

Apply the work-around for characteristic functions.

 newtype CharacteristicFunction e = CF {unCF :: e - Bool}

 instance Eq e = Collects e CharacteristicFunction where
   empty  = CF (\y - False)
   insert x c = CF (\y - x == y || unCF c x)
   member x c = unCF c x

Apply the work-around for bit sets. The dummy type variable "a" is
needed to make "BitSet b" a type constructor. (I've also generalized
your example from Char to Enum.)

 newtype Bits b = BitSet b a = BS {unBS :: b}

 instance (Enum e, Bits b) = Collects e (BitSet b) where
   empty  = BS (bit 0)
   insert x c = BS (setBit (unBS c) (fromEnum x))
   member x c = testBit (unBS c) (fromEnum x)

For the hash-table example I am pretty sure that the work-around works
as well, even though I could not figure out your intended
implementation.

Of course this is just a work-around and does not make functional
dependencies superfluous.

Regards,

Heribert.





RE: Functional Dependencies

1999-09-12 Thread Mark P Jones

Hi Heribert,

Thanks for your feedback!

| at the end of section 2 of http://www.cse.ogi.edu/~mpj/fds.html you
| might want to mention that there is a "standard" work-around whenever a
| type constructor is needed but not available: Introduce a newtype.

Yes, an in fact this idea is mentioned at the end of the constructor
classes paper!).  But it doesn't always work, and, even when it does,
you have to deal with the extra newtype constructors in both types and
terms.  The BitSet example shows when it doesn't work ... your reworking
of that example depended on generalizing the collection type to add an
extra parameter.  But suppose that you didn't want to, or couldn't, make
that generalization.  For example, this might occur (and indeed, has
occurred in some of our experiments at OGI) in programs that package up
somebody else's code to be used via a class.  And if you can't generalize,
then you're stuck.

| For the hash-table example I am pretty sure that the work-around works
| as well, even though I could not figure out your intended
| implementation.

For the hash table example, one possible newtype encoding might be
as follows:

   newtype HTable bucket a = Array Int (bucket a)
   instance (Hashable a, Collects a b)
  = Collects a (HTable b a) where ...

But this has some problems too ... suppose (somewhat bizarrely in
this case perhaps) that you wanted to use a composition of two
collection types to build the bucket type.  The type of the
corresponding collection would be: Array Int (outer (inner a)).
This would work just fine with the functional dependencies version,
but for the constructor classes version you'd have to introduce
yet another newtype and instance:

   newtype Compose f g x = Comp (f (g x))
   instance (Collects a g, Collects (g a) f)
  = Collects a (Comp f g) where ...

And so on ...

| Of course this is just a work-around and does not make functional
| dependencies superfluous.

That's true.  There are plenty of things you can do with dependencies
that you can't do with constructor classes, and vice versa.

I picked the Collects example because I thought it would be something
that would be reasonably familiar, but perhaps it has the danger of
giving people the impression that functional dependencies are an
alternative to constructor classes.  That's unfortunate because they're
really pretty orthogonal.

All the best,
Mark