Send Beginners mailing list submissions to
        beginners@haskell.org

To subscribe or unsubscribe via the World Wide Web, visit
        http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
        beginners-requ...@haskell.org

You can reach the person managing the list at
        beginners-ow...@haskell.org

When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."


Today's Topics:

   1. Re:  question on types (Gary Klindt)
   2. Re:  question on types (Jake Penton)
   3. Re:  question on types (Daniel Seidel)
   4. Re:  question on types (James Cook)
   5. Re:  question on types (Jake Penton)
   6. Re:  question on types (Daniel Seidel)
   7. Re:  question on types (James Cook)


----------------------------------------------------------------------

Message: 1
Date: Fri, 29 Jul 2011 12:54:37 +0200
From: Gary Klindt <gary.kli...@uni-konstanz.de>
Subject: Re: [Haskell-beginners] question on types
To: beginners@haskell.org
Message-ID: <4e32916d.70...@uni-konstanz.de>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed

So, why is it possible to work with the map :: (a -> b) -> [a] -> [b] 
function? One can use it with list of number and functions on numbers, 
can't one.




------------------------------

Message: 2
Date: Fri, 29 Jul 2011 07:27:28 -0400
From: Jake Penton <d...@arqux.com>
Subject: Re: [Haskell-beginners] question on types
To: Haskell Beginners <beginners@haskell.org>
Message-ID: <beee9c9d-644e-4e2c-a9bd-dda076189...@arqux.com>
Content-Type: text/plain; charset=us-ascii


On 2011-07-29, at 6:54 AM, Gary Klindt wrote:

> So, why is it possible to work with the map :: (a -> b) -> [a] -> [b] 
> function? One can use it with list of number and functions on numbers, can't 
> one.
> 

Yeah. Your question is pretty much an example of what what troubling me in my 
original post. And frankly, I doubt that my reasoning on this will get 
straightened out until I have studied the type system more thoroughly.

Naively, the difference I see between your example using map and my original 
post is that I was *defining*  f:

f::a
f = 1

which, I suppose, is quite a bit different than *calling* map. To parallel my 
example, one would (mistakenly) write something like this:

map::(a -> b)  -> [a] ->  [b]
map f lst = ['a','b','c']

The above gives the same message I got. It is tempting to think that " 
['a','b','c'] is a list of b's, so it should work", but that is clearly wrong.

- j -


------------------------------

Message: 3
Date: Fri, 29 Jul 2011 14:02:07 +0200
From: Daniel Seidel <d...@iai.uni-bonn.de>
Subject: Re: [Haskell-beginners] question on types
To: Jake Penton <d...@arqux.com>
Cc: Haskell Beginners <beginners@haskell.org>
Message-ID: <1311940927.13677.60.ca...@entwood.iai.uni-bonn.de>
Content-Type: text/plain

On Fri, 2011-07-29 at 07:27 -0400, Jake Penton wrote:
> On 2011-07-29, at 6:54 AM, Gary Klindt wrote:
> 
> > So, why is it possible to work with the map :: (a -> b) -> [a] -> [b] 
> > function? One can use it with list of number and functions on numbers, 
> > can't one.
> > 
> 
> Yeah. Your question is pretty much an example of what what troubling me in my 
> original post. And frankly, I doubt that my reasoning on this will get 
> straightened out until I have studied the type system more thoroughly.
> 
> Naively, the difference I see between your example using map and my original 
> post is that I was *defining*  f:
> 
> f::a
> f = 1
> 
> which, I suppose, is quite a bit different than *calling* map. To parallel my 
> example, one would (mistakenly) write something like this:
> 
> map::(a -> b)  -> [a] ->  [b]
> map f lst = ['a','b','c']
> 
> The above gives the same message I got. It is tempting to think that " 
> ['a','b','c'] is a list of b's, so it should work", but that is clearly wrong.

Maybe it helps to read the type signatures with explicit type
abstraction and instantiation.

f :: a 

means

f :: forall a. a

that is, I can choose any type for a, and f will have that type.
Let us make the choice explict: say if I use f in  "hello" ++ f, f will
be of type String, we can write f_{String} :: String, if I use it in
(5 :: Int) + f, it will be an Int, ie. f_{Int} :: Int, and so on. So f
must be typable to every type we can instantiate it with.

Now consider map. Here the thing different from f is, that type
variables occur not only on output positions, but also on input
positions of the function, ie. (a -> b) and [a] are at input positions.
And the type instantiation of map gets fixed by the inputs.
If we apply map to a function g :: Char -> Int, the concrete
instantiation of map is already fixed, we have to choose Int for a and
Char for b, ie apply

map_{Char, Int} :: (Char -> Int) -> [Char] -> [Int]

to g. Otherwise the program can't be typed.
In particular, that means that map g only takes lists with characters as
further argument and returns lists with integers.
What happens in your definition above is that you fix b already to
[Char] by your fixed output, so the map above can only be typed to

map :: forall a. (a -> b) -> [a] -> [Char]

Its maybe interesting to think about what functions of polymorphic type
can do. map for example is vastly  described by its type.
The type says it takes an arbitrary function mapping from a to b and a
list of elements of type a to return elements of type b.
Since map does not "know" what types a and b will be when it is called,
it can only apply f to values of type a to generate values of type b (or
use undefined).

For example

map f [] 

can only return a list with entries undefined, or f undefined.

Cheers,

Daniel.
> 
> - j -
> _______________________________________________
> Beginners mailing list
> Beginners@haskell.org
> http://www.haskell.org/mailman/listinfo/beginners




------------------------------

Message: 4
Date: Fri, 29 Jul 2011 09:23:27 -0400
From: James Cook <mo...@deepbondi.net>
Subject: Re: [Haskell-beginners] question on types
To: Jake Penton <d...@arqux.com>
Cc: Haskell Beginners <beginners@haskell.org>
Message-ID: <dcb35fc4-de10-4219-abf0-9ee59d6c2...@deepbondi.net>
Content-Type: text/plain; charset=us-ascii

On Jul 28, 2011, at 7:42 PM, Jake Penton wrote:

> I guess I interpret "f::a" to mean "f is some (any) type a". So why can't it 
> be whatever "1" is, which I suppose is Integer. What is the type system 
> looking for? And why does the constraint (Num a) make things ok?

This right here is the core of your confusion.  As you probably know, in all 
major typed "object-oriented" languages this is true; for example, in Java 
"Object foo;" means that "foo" is some type extending Object, and "List bar;" 
means that "bar" is some type satisfying the List interface.  But in typed 
functional languages, the mode of "quantification" has the opposite default.  
In Haskell, 'f::a' means "FOR EVERY type a, f can be that type".

This is universal quantification - just like the upside-down A ("for all") in 
logic, the type declaration must be true for all values of "a".  Sometimes it's 
important to be clear about which type of quantification you're talking about.  
When you do, "f :: a" would be written "f :: forall a. a", and what you had in 
mind would be written "f :: exists a. a".  The key difference is that in the 
"forall" case, the person using 'f' gets to choose its concrete type, but in 
the "exists" case the concrete type is chosen by the person defining it.

When type classes are involved, they just add restrictions to the type.  For 
example, "f :: Num a => a" still has an implied "forall", but the "Num a =>" 
part means that instead of "for every type a ...", you have "for every type a 
which implements Num ...".  Similarly, "f :: exists a. Num a => a" would mean 
"for some type a which implements Num ...".  So "f :: a; f = 1" doesn't work 
because it doesn't restrict the type enough.  By restricting the type to "Num a 
=> a", gain the ability to use the functions in the Num class, one of which is 
"fromInteger", which is called implicitly whenever you use a literal integer - 
that's what makes integer literals polymorphic in Haskell.  Similarly, "f = 
3.14" would require "f :: Fractional a => a" because "3.14" implicitly calls 
"fromRational", a function defined in the Fractional type class.

-- James

PS.  Although some Haskell compilers support them as optional language 
extensions, "forall" and "exists" are not official Haskell syntax - just 
conventions that humans use to keep things straight when thinking about the 
types.


------------------------------

Message: 5
Date: Fri, 29 Jul 2011 09:49:14 -0400
From: Jake Penton <d...@arqux.com>
Subject: Re: [Haskell-beginners] question on types
To: Haskell Beginners <beginners@haskell.org>
Message-ID: <612d87fb-2d4f-4f62-a47c-115658f75...@arqux.com>
Content-Type: text/plain; charset="us-ascii"


On 2011-07-29, at 9:23 AM, James Cook wrote:

> On Jul 28, 2011, at 7:42 PM, Jake Penton wrote:
> 
>> I guess I interpret "f::a" to mean "f is some (any) type a". So why can't it 
>> be whatever "1" is, which I suppose is Integer. What is the type system 
>> looking for? And why does the constraint (Num a) make things ok?
> 
> This right here is the core of your confusion.  As you probably know, in all 
> major typed "object-oriented" languages this is true; for example, in Java 
> "Object foo;" means that "foo" is some type extending Object, and "List bar;" 
> means that "bar" is some type satisfying the List interface.  But in typed 
> functional languages, the mode of "quantification" has the opposite default.  
> In Haskell, 'f::a' means "FOR EVERY type a, f can be that type".
> 
> This is universal quantification - just like the upside-down A ("for all") in 
> logic, the type declaration must be true for all values of "a".  Sometimes 
> it's important to be clear about which type of quantification you're talking 
> about.  When you do, "f :: a" would be written "f :: forall a. a", and what 
> you had in mind would be written "f :: exists a. a".  The key difference is 
> that in the "forall" case, the person using 'f' gets to choose its concrete 
> type, but in the "exists" case the concrete type is chosen by the person 
> defining it.
> 
> When type classes are involved, they just add restrictions to the type.  For 
> example, "f :: Num a => a" still has an implied "forall", but the "Num a =>" 
> part means that instead of "for every type a ...", you have "for every type a 
> which implements Num ...".  Similarly, "f :: exists a. Num a => a" would mean 
> "for some type a which implements Num ...".  So "f :: a; f = 1" doesn't work 
> because it doesn't restrict the type enough.  By restricting the type to "Num 
> a => a", gain the ability to use the functions in the Num class, one of which 
> is "fromInteger", which is called implicitly whenever you use a literal 
> integer - that's what makes integer literals polymorphic in Haskell.  
> Similarly, "f = 3.14" would require "f :: Fractional a => a" because "3.14" 
> implicitly calls "fromRational", a function defined in the Fractional type 
> class.
> 
> -- James
> 
> PS.  Although some Haskell compilers support them as optional language 
> extensions, "forall" and "exists" are not official Haskell syntax - just 
> conventions that humans use to keep things straight when thinking about the 
> types.

Well, there have been a couple of answers on this thread that suggest that a 
constraint/context will work. But this does not clear things up entirely for 
me. I probably do not understand your answer. But adding a constraint by itself 
does not of itself change things, although perhaps you are not suggesting that 
it would. 

For example, this does not compile:

f :: Fractional a => a
f = 3.14

This does:

class Foo a where
    f :: Fractional a => a

instance Foo Float where
    f = 3.14

So I infer that the reason that my example int the original post compiles is 
something other than merely the presence of the constraint. This compiles:

f :: Num a => a
f = 1

-------------- next part --------------
An HTML attachment was scrubbed...
URL: 
<http://www.haskell.org/pipermail/beginners/attachments/20110729/b35c46f7/attachment-0001.htm>

------------------------------

Message: 6
Date: Fri, 29 Jul 2011 16:02:33 +0200
From: Daniel Seidel <d...@iai.uni-bonn.de>
Subject: Re: [Haskell-beginners] question on types
To: Jake Penton <d...@arqux.com>
Cc: Haskell Beginners <beginners@haskell.org>
Message-ID: <1311948153.13677.63.ca...@entwood.iai.uni-bonn.de>
Content-Type: text/plain

On Fri, 2011-07-29 at 09:49 -0400, Jake Penton wrote:
> For example, this does not compile: 
> 
> f :: Fractional a => a 
> f = 3.14 

I can load this to ghci and also compile

f :: Fractional a => a
f = 3.14

main = print f

with ghc and call the program to return 3.14.

(ghc version 7.01)

Cheers, Daniel.





------------------------------

Message: 7
Date: Fri, 29 Jul 2011 10:58:46 -0400
From: James Cook <mo...@deepbondi.net>
Subject: Re: [Haskell-beginners] question on types
To: Jake Penton <d...@arqux.com>
Cc: Haskell Beginners <beginners@haskell.org>
Message-ID: <edef16b3-2de8-4d35-8460-bc8a58b78...@deepbondi.net>
Content-Type: text/plain; charset="us-ascii"

On Jul 29, 2011, at 9:49 AM, Jake Penton wrote:

> Well, there have been a couple of answers on this thread that suggest that a 
> constraint/context will work. But this does not clear things up entirely for 
> me. I probably do not understand your answer. But adding a constraint by 
> itself does not of itself change things, although perhaps you are not 
> suggesting that it would. 
> 
> For example, this does not compile:
> 
> f :: Fractional a => a
> f = 3.14

It should.  Is there something else in the file you're compiling which somehow 
conflicts?  What error does it print?

> This does:
> 
> class Foo a where
>     f :: Fractional a => a
> 
> instance Foo Float where
>     f = 3.14
> 
> So I infer that the reason that my example int the original post compiles is 
> something other than merely the presence of the constraint. This compiles:
> 
> f :: Num a => a
> f = 1

Actually, it is solely the presence of the constraint which makes it OK.  By 
constraining it, you're saying "f can produce a value of any type, so long as 
that type implements Num" - and by saying that, you get to rely on the compiler 
enforcing it, so you can use all the functions Num provides.  One of those 
functions is "fromInteger", which the compiler uses in the implementation of 
"1".  When you say "f = 1", the compiler interprets that as "f = fromInteger (1 
:: Integer)".  Without the constraint, you're not allowed to use "fromInteger" 
because that function doesn't exist for all types.

-- James
-------------- next part --------------
An HTML attachment was scrubbed...
URL: 
<http://www.haskell.org/pipermail/beginners/attachments/20110729/4b0e432c/attachment.htm>

------------------------------

_______________________________________________
Beginners mailing list
Beginners@haskell.org
http://www.haskell.org/mailman/listinfo/beginners


End of Beginners Digest, Vol 37, Issue 65
*****************************************

Reply via email to