A Very Simple Type Class Question

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

A Very Simple Type Class Question

Larry Lee
Hi

I have a very simple problem.
I have a class and want to define a function in that class that returns
a different instance of the same class.

I tried accomplishing this as follows:

     class A a where
       f :: A b => a -> b


This fails however when I try to instantiate it. For example:

     instance A String where
       f x = x


I get an error message that makes absolutely no sense to me:

     src/CSVTree.hs:12:9:
         Could not deduce (b ~ [Char])
         from the context (A b)
           bound by the type signature for f :: A b => String -> b
           at src/CSVTree.hs:12:3-9
           `b' is a rigid type variable bound by
               the type signature for f :: A b => String -> b
               at src/CSVTree.hs:12:3
         In the expression: x
         In an equation for `f': f x = x
         In the instance declaration for `A String'
     make: *** [compile] Error 1

Can someone please explain: how I can achieve my goal; and why my code
is failing; simply and in plain English.

Thanks,
Larry
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: A Very Simple Type Class Question

Andrew Gibiansky
When you declare a type signature such as

f :: C x => a -> b

there is an implicit "forall":

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

That is, the type signature must hold for all x such that C x holds. However, in your case, it only holds for String – while A String does hold, that is irrelevant, because the type signature states that it must hold for *any* x such that A x that the caller wants. To put it another way, the caller decides the "b" in that type signature, not the function implementation.

What you want is something like 

f :: exists x. C x => a -> x

so that f will return some unknown value such that you know it is an instance of C x.

Hope that helps,
Andrew

On Tue, Nov 11, 2014 at 12:59 PM, Larry Lee <[hidden email]> wrote:
Hi

I have a very simple problem.
I have a class and want to define a function in that class that returns a different instance of the same class.

I tried accomplishing this as follows:

    class A a where
      f :: A b => a -> b


This fails however when I try to instantiate it. For example:

    instance A String where
      f x = x


I get an error message that makes absolutely no sense to me:

    src/CSVTree.hs:12:9:
        Could not deduce (b ~ [Char])
        from the context (A b)
          bound by the type signature for f :: A b => String -> b
          at src/CSVTree.hs:12:3-9
          `b' is a rigid type variable bound by
              the type signature for f :: A b => String -> b
              at src/CSVTree.hs:12:3
        In the expression: x
        In an equation for `f': f x = x
        In the instance declaration for `A String'
    make: *** [compile] Error 1

Can someone please explain: how I can achieve my goal; and why my code is failing; simply and in plain English.

Thanks,
Larry
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: A Very Simple Type Class Question

Jochem Berndsen-3
In reply to this post by Larry Lee
Hi Larry,

On 11/11/2014 09:59 PM, Larry Lee wrote:

> Hi
>
> I have a very simple problem.
> I have a class and want to define a function in that class that
> returns a different instance of the same class.
>
> I tried accomplishing this as follows:
>
>     class A a where
>       f :: A b => a -> b
>
>
> This fails however when I try to instantiate it. For example:
>
>     instance A String where
>       f x = x
>
>
> I get an error message that makes absolutely no sense to me:
>

f has type
   (A a, A b) => a -> b.

Both a and b can be thosen by the caller.
If you try to create an instance of A like you did, this will not type
check, as you have only provided a function of type
    String -> String,
whereas a function of type
    A b => String -> b
(for *all* b) is required.

I hope that clears things up a little.

Thanks, Jochem

--
Jochem Berndsen | [hidden email]

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: A Very Simple Type Class Question

Frank Staals
In reply to this post by Larry Lee
Larry Lee <[hidden email]> writes:

> Hi
>
> I have a very simple problem.
> I have a class and want to define a function in that class that returns a
> different instance of the same class.
>
> I tried accomplishing this as follows:
>
>     class A a where
>       f :: A b => a -> b

The only possible implementation for function f will be const
undefined. Your function f promises that given a value of type a, it can
return a value of *any* type b, as long as b is an instance of typeclass
A. So, once we are given a value of type a, we have to produce a value
of type b, however, we don't know what type b is! The only thing that we
know about things of type b is that they are an instance of A. This is
not enough information to be able to produce something of type b.

> This fails however when I try to instantiate it. For example:
>
>     instance A String where
>       f x = x
>
>
> I get an error message that makes absolutely no sense to me:
>
>     src/CSVTree.hs:12:9:
>         Could not deduce (b ~ [Char])
>         from the context (A b)
>   <snip>


See the above: you are producing of type String. However, according to
the type signature, you should be able to produce something of an
arbitrary type b. Clearly that is not possible.

I am guessing that once you know the type a, you also know what the
output type b will be. If that is the case then you can use type
families:

class A a where
  type B a
  f :: a -> B a

instance A String where
  type B String = String
  f = id


Hope this helps.

Regards,

--

- Frank
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: A Very Simple Type Class Question

Kostiantyn Rybnikov
In reply to this post by Larry Lee
Larry,

By your definition

f x = x

this function returns whatever it got in it's argument, thus:
1. compiler infers that it's argument is of type String from class-definition
2. String is actually a type-synonim for list of chars
   
        type String = [Char]

3. So now, on one hand function is returning something of a concrete type [Char], and on the other (from class-definition) it should be some type only restricted by operations on type-class.

Regarding your question on "how to do things properly" -- I'm not sure what exactly are you trying to achieve. Could you describe a problem you're trying to solve?

If you want to return something of type b, which is only constrainted by being an instance of a type-class A, then you need to create it with a function defined in class A. But since only function is f, it's not enough. Here's an example of solution for the original "return something of another instance" problem:

{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE TypeSynonymInstances #-}

class A a where
  f :: A b => a -> b
  def :: a

instance A Int where
  f x = def
  def = 4

instance A String where
  f x = def
  def = "asd"

main :: IO ()
main = print $ (f "asd" :: Int)

Cheers.

On Tue, Nov 11, 2014 at 10:59 PM, Larry Lee <[hidden email]> wrote:
Hi

I have a very simple problem.
I have a class and want to define a function in that class that returns a different instance of the same class.

I tried accomplishing this as follows:

    class A a where
      f :: A b => a -> b


This fails however when I try to instantiate it. For example:

    instance A String where
      f x = x


I get an error message that makes absolutely no sense to me:

    src/CSVTree.hs:12:9:
        Could not deduce (b ~ [Char])
        from the context (A b)
          bound by the type signature for f :: A b => String -> b
          at src/CSVTree.hs:12:3-9
          `b' is a rigid type variable bound by
              the type signature for f :: A b => String -> b
              at src/CSVTree.hs:12:3
        In the expression: x
        In an equation for `f': f x = x
        In the instance declaration for `A String'
    make: *** [compile] Error 1

Can someone please explain: how I can achieve my goal; and why my code is failing; simply and in plain English.

Thanks,
Larry
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: A Very Simple Type Class Question

James M
In reply to this post by Larry Lee
First, there is an even simpler case that won't work:

class A a where
   foo :: a -> b

The question is what is 'b'. According to this b can be anything not something specific. If you want 'b' to be something specific in must appear as part of the type class declaration.

To do what you want to do, you could use the extension MultiParamTypeClasses.

class A a

class (A a, A b) => B a b where
   foo :: a -> b

instance A Int

instance B Int Int where
    foo = id


Second, Haskell does not by default allow for type synonyms in instance declarations. String is a type synonym of [Char]. If you want to use String in instance declarations use the extension TypeSynonymInstances and FlexibleInstances.

instance A String

instance A String String where
    foo = id


James

On Tue, Nov 11, 2014 at 12:59 PM, Larry Lee <[hidden email]> wrote:
Hi

I have a very simple problem.
I have a class and want to define a function in that class that returns a different instance of the same class.

I tried accomplishing this as follows:

    class A a where
      f :: A b => a -> b


This fails however when I try to instantiate it. For example:

    instance A String where
      f x = x


I get an error message that makes absolutely no sense to me:

    src/CSVTree.hs:12:9:
        Could not deduce (b ~ [Char])
        from the context (A b)
          bound by the type signature for f :: A b => String -> b
          at src/CSVTree.hs:12:3-9
          `b' is a rigid type variable bound by
              the type signature for f :: A b => String -> b
              at src/CSVTree.hs:12:3
        In the expression: x
        In an equation for `f': f x = x
        In the instance declaration for `A String'
    make: *** [compile] Error 1

Can someone please explain: how I can achieve my goal; and why my code is failing; simply and in plain English.

Thanks,
Larry
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: A Very Simple Type Class Question

Alejandro Serrano Mena
In reply to this post by Larry Lee
The problem is that the type of f is

f :: (A a, A b) => a -> b

This means that given an 'a', you need to create a function which works for *any* b in A.

However, the function you implement is of type `f :: String -> String`, not of type `f :: A b => String -> b`, as needed. If you were to implement the function in that way, you could use:

class A a where
  f :: a -> a

2014-11-11 21:59 GMT+01:00 Larry Lee <[hidden email]>:
Hi

I have a very simple problem.
I have a class and want to define a function in that class that returns a different instance of the same class.

I tried accomplishing this as follows:

    class A a where
      f :: A b => a -> b


This fails however when I try to instantiate it. For example:

    instance A String where
      f x = x


I get an error message that makes absolutely no sense to me:

    src/CSVTree.hs:12:9:
        Could not deduce (b ~ [Char])
        from the context (A b)
          bound by the type signature for f :: A b => String -> b
          at src/CSVTree.hs:12:3-9
          `b' is a rigid type variable bound by
              the type signature for f :: A b => String -> b
              at src/CSVTree.hs:12:3
        In the expression: x
        In an equation for `f': f x = x
        In the instance declaration for `A String'
    make: *** [compile] Error 1

Can someone please explain: how I can achieve my goal; and why my code is failing; simply and in plain English.

Thanks,
Larry
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: A Very Simple Type Class Question

Taylor Hedberg
In reply to this post by Larry Lee
The caller of your function f, rather than the implementation of f, gets to decide which instance of A f should return. In other words, f's implementation must be polymorphic in its return type. Your example f x = x does not satisfy that property. That implementation has type f :: A a => a -> a, not the required type f :: (A a, A b) => a -> b.

The error message is saying that, from the class definition, GHC has deduced that f must return a value of type A b => b, but your implementation is returning a String (a.k.a. [Char]) instead. The notation b ~ [Char] means "b is equivalent to [Char]".

On Tue, Nov 11, 2014 at 12:59 PM, Larry Lee <[hidden email]> wrote:
Hi

I have a very simple problem.
I have a class and want to define a function in that class that returns a different instance of the same class.

I tried accomplishing this as follows:

    class A a where
      f :: A b => a -> b


This fails however when I try to instantiate it. For example:

    instance A String where
      f x = x


I get an error message that makes absolutely no sense to me:

    src/CSVTree.hs:12:9:
        Could not deduce (b ~ [Char])
        from the context (A b)
          bound by the type signature for f :: A b => String -> b
          at src/CSVTree.hs:12:3-9
          `b' is a rigid type variable bound by
              the type signature for f :: A b => String -> b
              at src/CSVTree.hs:12:3
        In the expression: x
        In an equation for `f': f x = x
        In the instance declaration for `A String'
    make: *** [compile] Error 1

Can someone please explain: how I can achieve my goal; and why my code is failing; simply and in plain English.

Thanks,
Larry
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: A Very Simple Type Class Question

Tom Ellis
In reply to this post by Larry Lee
On Tue, Nov 11, 2014 at 03:59:50PM -0500, Larry Lee wrote:

> I have a very simple problem.
> I have a class and want to define a function in that class that
> returns a different instance of the same class.
>
> I tried accomplishing this as follows:
>
>     class A a where
>       f :: A b => a -> b
>
>
> This fails however when I try to instantiate it. For example:
>
>     instance A String where
>       f x = x

The `f` that you defined has type `String -> String`.  However, given the
definition of the class `A` it should have been of type `A b => String ->
b`.

What exactly are you trying to do here?  This is probably not the way to go
about it.

Tom
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: A Very Simple Type Class Question

Ivan Lazar Miljenovic
In reply to this post by Larry Lee
On 12 November 2014 07:59, Larry Lee <[hidden email]> wrote:

> Hi
>
> I have a very simple problem.
> I have a class and want to define a function in that class that returns a
> different instance of the same class.
>
> I tried accomplishing this as follows:
>
>     class A a where
>       f :: A b => a -> b

This type signature says "I can convert my instance of type `a' to any
instance of this type class `b'... as chosen by the *caller* of this
function".

i.e. if you have instances for Foo, Bar and Baz, then "f Foo" isn't
fixed to just Bar: the caller can choose any instance it likes (which
is usually not what you want).

>
>
> This fails however when I try to instantiate it. For example:
>
>     instance A String where
>       f x = x

This instance only works if the `b' in the type signature of `f' is
also String, rather than being chosen by the caller.

>
>
> I get an error message that makes absolutely no sense to me:
>
>     src/CSVTree.hs:12:9:
>         Could not deduce (b ~ [Char])
>         from the context (A b)
>           bound by the type signature for f :: A b => String -> b
>           at src/CSVTree.hs:12:3-9
>           `b' is a rigid type variable bound by
>               the type signature for f :: A b => String -> b
>               at src/CSVTree.hs:12:3
>         In the expression: x
>         In an equation for `f': f x = x
>         In the instance declaration for `A String'
>     make: *** [compile] Error 1

This is saying "The instance definition requires the `b' type to be
[Char] (i.e. String), but there's no requirement/ability in the
definition of the type to have such a constraint/requirement."

>
> Can someone please explain: how I can achieve my goal; and why my code is
> failing; simply and in plain English.

Depending on what exactly you want, there are three options:

* If you want each type to convert to itself, then change the type of
`f' to be just "a -> a"

* If you want a one-to-many mapping (i.e. given `a', I know there's
precisely one possible value of `b'), then use either Multi-Param Type
Classes (MPTCs) + Functional Dependencies or else an associated Type
Family alias within the type class to denote that relationship.

* If you have a many-to-many relationship (Foo can convert to Foo or
Baz, Bar can convert only to Baz and Baz can convert to anything),
then use an MPTC (though this will in general require an instance for
every possible pairing).

>
> Thanks,
> Larry
> _______________________________________________
> Haskell-Cafe mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/haskell-cafe



--
Ivan Lazar Miljenovic
[hidden email]
http://IvanMiljenovic.wordpress.com
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe