I am pretty sure I have a good handle on type classes, but this one is perplexing me in Haskell. I created custom Tuples called Tuple2 and Tuple3 (I know Haskell already has Tuples, just thought I would create my own for this exercise). Then I wanted to create a type class that would have a method called first that would get the first element of the tuple regardless of what kind of Tuple it is. Tuple2, Tuple3, etc.
Here is what I have: data Tuple3 a b c = Tuple3 a b c deriving (Show) data Tuple2 a b = Tuple2 a b deriving (Show) class Indexable idx where first :: idx c -> a instance Indexable (Tuple2 a) where first (Tuple2 a b) = a In my main, I try to get call putStrLn $ show $ first $ Tuple2 1 "One" I was greeted with the following trace: Couldn't match expected type ‘a1’ with actual type ‘a’ ‘a’ is a rigid type variable bound by the instance declaration at TypeClasses.hs:35:10 ‘a1’ is a rigid type variable bound by the type signature for first :: Tuple2 a c -> a1 at TypeClasses.hs:36:4 Relevant bindings include a :: a (bound at TypeClasses.hs:36:18) first :: Tuple2 a c -> a1 (bound at TypeClasses.hs:36:4) In the expression: a In an equation for ‘first’: first (Tuple2 a b) = a Help is appreciated. _______________________________________________ Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
Quick adjustment, playing around too much with it, that should be: class Indexable idx where first :: idx a -> a Problem still exists. On Sun, Jan 24, 2016 at 11:25 PM, Daniel Hinojosa <[hidden email]> wrote:
_______________________________________________ Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
Got it to work this way but it got the wrong one. Still looking. instance Indexable (Tuple2 a) where first (Tuple2 b a) = a On Sun, Jan 24, 2016 at 11:39 PM, Daniel Hinojosa <[hidden email]> wrote:
_______________________________________________ Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
Hello Daniel,
it works with these tweaks: -- begin {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-} module TupInst where data Tuple3 a b c = Tuple3 a b c deriving (Show) data Tuple2 a b = Tuple2 a b deriving (Show) class Indexable idx a where first :: idx -> a instance Indexable (Tuple2 a b) a where first (Tuple2 a0 b0) = a0 instance Indexable (Tuple3 a b c) a where first (Tuple3 a0 b0 c0) = a0 -- end call it in ghci like this: first $ Tuple3 (1::Int) 'a' False::Int _______________________________________________ Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
Ah. I had a suspicion it had to do with extensions. Got to study up on it. Thanks On Jan 25, 2016 12:42 AM, "Imants Cekusins" <[hidden email]> wrote:
Hello Daniel, _______________________________________________ Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
In reply to this post by Daniel Hinojosa
May I suggest using FunctionalDependencies
https://wiki.haskell.org/Functional_dependencies The class declaration is changed to class Indexable idx a | idx -> a where first :: idx -> a This just means that *a* is fully determined by idx (your tuple). Hence, instead of using as suggested first $ Tuple3 (1::Int) 'a' False::Int You can simplify and let the inference do its magic and use: first $ Tuple3 1 'a' False On Mon, Jan 25, 2016 at 8:42 AM, Imants Cekusins <[hidden email]> wrote: > Hello Daniel, > > it works with these tweaks: > > -- begin > > {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-} > module TupInst where > > > data Tuple3 a b c = Tuple3 a b c deriving (Show) > > data Tuple2 a b = Tuple2 a b deriving (Show) > > class Indexable idx a where > first :: idx -> a > > > instance Indexable (Tuple2 a b) a where > first (Tuple2 a0 b0) = a0 > > > instance Indexable (Tuple3 a b c) a where > first (Tuple3 a0 b0 c0) = a0 > > -- end > > call it in ghci like this: > > first $ Tuple3 (1::Int) 'a' False::Int > _______________________________________________ > Beginners mailing list > [hidden email] > http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
> class Indexable idx a | idx -> a where Cutting in to say thanks -- I've had a vague notion of what fundeps do but this really gelled it for me! _______________________________________________ Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
Thank you Guillaume
fun deps are new for me too. quoting from the above wiki link: -- Read as: "container" type determines "elem" type. class Extract container elem | container -> elem where extract :: container -> elem The functional dependency "container -> elem" promises that we won't declare multiple instances with the same "container" type. Without the functional dependency, both instances above would be allowed, and the type of v would be potentially ambiguous. Even if only one instance is defined, the type system will not figure it out without the functional dependency. _______________________________________________ Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
On Wed, Jan 27, 2016 at 9:41 AM, Imants Cekusins <[hidden email]> wrote:
> Thank you Guillaume > > fun deps are new for me too. > > quoting from the above wiki link: > > > -- Read as: "container" type determines "elem" type. > class Extract container elem | container -> elem where > extract :: container -> elem > The functional dependency "container -> elem" promises that we won't > declare multiple instances with the same "container" type. > > > > Without the functional dependency, both instances above would be > allowed, and the type of v would be potentially ambiguous. Even if > only one instance is defined, the type system will not figure it out > without the functional dependency. At first this is weird because we have the feeling that `instance Indexable (Tuple2 a b) a` fully qualifie the second type "a" as equivalent to the first subtype "a" of Tuple2. This is True for this instance, but the typechecker does not try to find one instance which match, it tries to find if , knowing the class definition, it is possible to be sure that there will only be one instance matching, and this is not the case because someone can easily define `instance Indexable (Tuple2 a b) String`. That's something I really like about this mecanism, is that adding new instances later cannot change the behavior of previous one. [A bit of digression] Actually, I don't know why, but at first though I always think in the wrong direction when reasoning about types. FunctionalDependencies is one example, but I had the same issue when I tried to understand why `fmap` cannot work on unboxed Vector. When reading the types, `fmap :: Functor f => (a -> b) -> f a -> f b`, I was understanding that it accepts any `a` as input. It was working on `Vector a`, but not on `Unbox a => Vector a` which appears more constrained, so if `fmap` was accepting any `a` as argument, it will certainly accept an `Unbox a` which is more constrained. But actually it works the opposite, `fmap` types means that `a` should be anything, and not something constrained. _______________________________________________ Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
> `fmap` types mean that `a` should be anything, and not something
constrained. just wondering: is it something specific to Functor class or does this hold for any class declaration: (a -> b) is not the same as ... a => (a -> b) in other words, if class expects (a -> b) with any a, instance must not constrain a. as opposed to ... a => a -> b which seems ok _______________________________________________ Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
On Wed, Jan 27, 2016 at 11:11 AM, Imants Cekusins <[hidden email]> wrote:
>> `fmap` types mean that `a` should be anything, and not something > constrained. > > just wondering: is it something specific to Functor class or does this > hold for any class declaration: > > (a -> b) > is not the same as > ... a => (a -> b) a => (a -> b) does not really mean anything as far as I know because a is not a constraint (i.e: a typeclass). Perhaps you mean something such as Constraint a => (a -> b) > in other words, if class expects (a -> b) with any a, instance must > not constrain a. However I discovered the `ConstraintKinds` extension which may improve the situation. -- G. _______________________________________________ Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
Le mer. 27 janv. 2016 à 14:29, Guillaume Bouchard <[hidden email]> a écrit : However I discovered the `ConstraintKinds` extension which may improve It does, it is in fact quite easy in modern Haskell to write a typeclass analogue to a functor but which may have further constraints on the types contained. But it won't be the historic "Functor" typeclass which is ubiquitous in the Haskell packages... {-# LANGUAGE ConstraintKinds, TypeFamilies #-} module ConstrainedFunctor where import GHC.Exts (Constraint) import qualified Data.Vector.Unboxed as V class CFunctor f where type FConstraint f x :: Constraint type instance FConstraint f x = () cfmap :: (FConstraint f a, FConstraint f b) => (a -> b) -> f a -> f b instance CFunctor V.Vector where type FConstraint V.Vector x = V.Unbox x cfmap f v = V.map f v doubleVector :: V.Vector Int -> V.Vector Int doubleVector = cfmap (*2) -- Jedaï _______________________________________________ Beginners mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners |
Free forum by Nabble | Edit this page |