Hello all, I'm trying to implement some simple natural language semantics with Haskell (Hugs), and I'm running into trouble with type classes. Here's what I want to do: Suppose that x :: a -> b y :: a then I want to write apply x y = x y :: b Moreover, if x :: a y :: a -> b I also want to write apply x y = y x :: b So far I was able to implement what I want, as follows: class Applicable a b c | a b -> c where apply :: a -> b -> c instance Applicable (a -> b) a b where apply = ($) instance Applicable a (a -> b) b where apply = flip ($) The code above allows me to say int :: Int -> Int int = id test = apply (int 3) (apply ((+)::Int->Int->Int) (int 5)) which results in test == 8. Now, suppose that m is a Monad. If x :: m a y :: m (a -> b) I want to write apply x y = do x' <- x; y' <- y; return x y :: m b Similarly, if x :: m (a -> b) y :: m a I want to write apply x y = do x' <- x; y' <- y; return y x :: m b In general, if apply :: a -> b -> c works, I also want apply :: m a -> m b -> m c to work, by apply = liftM2 apply Thus I attempted: import Monad instance (Monad m, Applicable a b c) => Applicable (m a) (m b) (m c) where apply = liftM2 apply test2 = apply [int 3] (apply [(+)::Int->Int->Int] [int 5]) But Hugs said: ERROR M4.hs:23 - Unresolved top-level overloading *** Binding : test2 *** Outstanding context : Applicable Int (Int -> Int) b What's wrong? Given that class Applicable a b c | a b -> c, shouldn't Hugs be able to figure out automatically what type b would result in Applicable Int (Int -> Int) b? Thanks in advance... -- Edit this signature at http://rodimus.digitas.harvard.edu/cgi-bin/ken/sig "The day Microsoft makes something that doesn't suck is probably the day they start making vacuum cleaners" - Ernst Jan Plugge
On Thu, Feb 15, 2001 at 02:37:09PM -0500, Ken Shan wrote:
test2 = apply [int 3] (apply [(+)::Int->Int->Int] [int 5])
What's strange is that when I tried this just now, the identical line at the interpreter prompt returned the correct answer [8]. This is with Hugs from February 2000; I'm about to download and try the new version. (I find these type dependencies great fun to experiment with, but it's unfortunate that only Hugs supports them. Any chance ghc or nhc will support them soon?) Best, Dylan
On Thu, Feb 15, 2001 at 09:08:13PM -0500, Dylan Thurston wrote:
On Thu, Feb 15, 2001 at 02:37:09PM -0500, Ken Shan wrote:
test2 = apply [int 3] (apply [(+)::Int->Int->Int] [int 5])
What's strange is that when I tried this just now, the identical line at the interpreter prompt returned the correct answer [8]. This is with Hugs from February 2000; I'm about to download and try the new version.
The same thing happens with the latest Hugs (February 2001). I've attached the complete file. The exact error message is Reading file "/home/dpt/haskell/progs/test.hs": Parsing........................................................................ Dependency analysis............................................................ Type checking ERROR /home/dpt/haskell/progs/test.hs:18 - Unresolved top-level overloading *** Binding : test *** Outstanding context : Applicable Int (Int -> Int) b Again, commenting out the definition of 'test' and typing the same thing at the interpreter prompt works fine. Best, Dylan Thurston
On 2001-02-15T21:38:54-0500, Dylan Thurston wrote:
On Thu, Feb 15, 2001 at 02:37:09PM -0500, Ken Shan wrote:
test2 = apply [int 3] (apply [(+)::Int->Int->Int] [int 5])
What's strange is that when I tried this just now, the identical line at the interpreter prompt returned the correct answer [8]. This is with Hugs from February 2000; I'm about to download and try the new version. The same thing happens with the latest Hugs (February 2001).
I tried making things into functions, and that also helped. I.e., instead of saying "test = ..." and "test2 = ...", I said "test _ = ..." and "test2 _ = ..."; both worked. Can someone please explain this behavior? I don't understand type classes very well... -- Edit this signature at http://rodimus.digitas.harvard.edu/cgi-bin/ken/sig "The day Microsoft makes something that doesn't suck is probably the day they start making vacuum cleaners" - Ernst Jan Plugge
Thu, 15 Feb 2001 21:08:13 -0500, Dylan Thurston <dpt@math.harvard.edu> pisze:
On Thu, Feb 15, 2001 at 02:37:09PM -0500, Ken Shan wrote:
test2 = apply [int 3] (apply [(+)::Int->Int->Int] [int 5])
What's strange is that when I tried this just now, the identical line at the interpreter prompt returned the correct answer [8]. This is with Hugs from February 2000; I'm about to download and try the new version.
The monomorphism restriction bites again. A variable binding without a type signature is monomorphic... It's another question whether the error is OK, but this explains the difference between the toplevel definition and expression entered at the prompt. Anyway, adding an explicit type signature should help. ghc and nhc98 can be told to ignore the monomorphism restriction. -- __("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/ \__/ ^^ SYGNATURA ZASTÊPCZA QRCZAK
On 2001-02-16T07:56:42+0000, Marcin 'Qrczak' Kowalczyk wrote:
test2 = apply [int 3] (apply [(+)::Int->Int->Int] [int 5])
The monomorphism restriction bites again. A variable binding without a type signature is monomorphic...
But, but, but... The type *is* monomorphic, in the sense that it can only be test :: Int, test2 :: [Int]... *sob* Then again, this is a conclusion that can only be reached after dependencies in type classes are taken into account. Given that dependencies are an experimental feature, does this count as a bug? Or should the monomorphism restriction be taken to mean, as Hugs seems to do, "monomorphism after unification, as in standard Haskell"?
ghc and nhc98 can be told to ignore the monomorphism restriction.
Thanks! -- Edit this signature at http://rodimus.digitas.harvard.edu/cgi-bin/ken/sig "The day Microsoft makes something that doesn't suck is probably the day they start making vacuum cleaners" - Ernst Jan Plugge
On Thu, 15 Feb 2001, Ken Shan wrote:
Hello all,
I'm trying to implement some simple natural language semantics with Haskell (Hugs), and I'm running into trouble with type classes. Here's what I want to do: Suppose that
x :: a -> b y :: a
then I want to write
apply x y = x y :: b
Moreover, if
x :: a y :: a -> b
I also want to write
apply x y = y x :: b
This is ad hoc overloading, and IMHO bad style, at least in haskell. As I understand it, haskell type classes were never intended to support this. You will run into problems sooner or later if you think you can use type classes to overload like you can in C++. Type classes are (as I understand it) (even with current extensions) supposed to support a kind of less ad hoc overloading where the arguments always play the same role. /Lars L
On 2001-02-16T09:52:41+0100, Lars Lundgren wrote:
This is ad hoc overloading, and IMHO bad style, at least in haskell. As I understand it, haskell type classes were never intended to support this.
Well, whether this is ad hoc overloading depends on whether you find ad hoc this particular theory of how sentence fragments in natural language combine with each other... I don't particularly want to overload like I can in C++; I just want to overload like people (are theorized by some linguists to) overload in English. In any case, I can certainly dump everything (Int, Int->Int->Int, and whatnot) into a single sum type, and perform my own type checking, but I'd rather not duplicate the work that Haskell has done for me. A few minutes ago I came up with the idea of turning polymorphic types into non-polymorphic types using sum types, thus allowing polymorphic values, but I'll have to make things more concrete before I can say more about this idea. -- Edit this signature at http://rodimus.digitas.harvard.edu/cgi-bin/ken/sig "The day Microsoft makes something that doesn't suck is probably the day they start making vacuum cleaners" - Ernst Jan Plugge
On Sat, 17 Feb 2001, Ken Shan wrote:
On 2001-02-16T09:52:41+0100, Lars Lundgren wrote:
This is ad hoc overloading, and IMHO bad style, at least in haskell. As I understand it, haskell type classes were never intended to support this.
Well, whether this is ad hoc overloading depends on whether you find ad hoc this particular theory of how sentence fragments in natural language combine with each other...
That particular theory is certainly unknown to the type class mechanism and, I guess, hard to encode in it.
I don't particularly want to overload like I can in C++; I just want to overload like people (are theorized by some linguists to) overload in English.
That is very fine, I just wanted to warn you that type classes might not be the best tool for the job. It's hard to appreciate type classes if you think it is something it isn't. A screwdriver is a very useful tool, but if you try to use it as a hammer you will get dissapointed. Overloading in natural languages is very free, and very hard to formalize. Overloading in haskell is intentionally much more restricted. The overloading in C++ might be a better fit.
In any case, I can certainly dump everything (Int, Int->Int->Int, and whatnot) into a single sum type, and perform my own type checking, but I'd rather not duplicate the work that Haskell has done for me. A few minutes ago I came up with the idea of turning polymorphic types into non-polymorphic types using sum types, thus allowing polymorphic values, but I'll have to make things more concrete before I can say more about this idea.
You lost me. I do not understand the connection between this and overloading. I.e overloading is about syntax. /Lars L
participants (4)
-
Dylan Thurston -
Ken Shan -
Lars Lundgren -
qrczak@knm.org.pl