Send Beginners mailing list submissions to
        [email protected]

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
        [email protected]

You can reach the person managing the list at
        [email protected]

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


Today's Topics:

   1. Re:  type of zipWithPlus (Sebastian Hungerecker)
   2. Re:  fromIntegral (Daniel Fischer)
   3. Re:  fromIntegral (Daniel Fischer)
   4. Re:  Re: Beginners Digest, Vol 28, Issue 5 (Daniel Fischer)


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

Message: 1
Date: Sat, 02 Oct 2010 13:22:48 +0200
From: Sebastian Hungerecker <[email protected]>
Subject: Re: [Haskell-beginners] type of zipWithPlus
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed

On 01.10.2010 05:43, Russ Abbott wrote:
>> let (zipWithPlus :: Num a =>  [a] ->  [a] ->  [a]) = zipWith (+)
>>      
> <interactive>:1:5:
>      Illegal signature in pattern: (Num a) =>  [a] ->  [a] ->  [a]
>          Use -XScopedTypeVariables to permit it
>    

It works if you write it as:
let zipWithPlus :: Num a => [a] -> [a] -> [a]; zipWithPlus = zipWith (+)

I.e. writing it exactly as you would in a file (inside a do-block),
but with a semicolon where the linebreak would be.


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

Message: 2
Date: Sat, 2 Oct 2010 16:09:01 +0200
From: Daniel Fischer <[email protected]>
Subject: Re: [Haskell-beginners] fromIntegral
To: [email protected]
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain;  charset="utf-8"

On Saturday 02 October 2010 07:24:38, Russ Abbott wrote:
> Thanks. I'm still wondering what [ ] refers to.

That depends where it appears. Leaving aside []'s existence as a type 
constructor, it can refer to
- an empty list of specific type
- an empty list of some constrained type (say, [] :: Num a => [a])
- an empty list of arbitrary type.

At any point where it is finally used (from main or at the interactive 
prompt), it will be instantiated at a specific type (at least in GHC).

At the Haskell source code level, [] is an expression that can have any 
type [a].

At the Core level (first intermediate representation in GHC's compilation 
process, still quite similar to Haskell), [] is a function which takes a 
type ty as argument and produces a value of type [ty].

At the assembly level, there are no types anymore, and I wouldn't be 
surprised if all occurrences of [] compiled down to the same bit of data.

> I can load the following file without error.
>
> null' xs = xs == [ ]

Let's see what Core the compiler produces of that:

Null.null' :: forall a_adg.
              (GHC.Classes.Eq a_adg) =>
              [a_adg] -> GHC.Bool.Bool

--Straightforward, except perhaps the name mangling to produce unique 
names.

GblId
[Arity 1]

--Lives at the top level and takes one argument.

Null.null' =
  \ (@ a_ahp) ($dEq3_aht :: GHC.Classes.Eq a_ahp) ->

--Here it gets interesting, at this level, it takes more than one argument, 
the first two are given here, a type a_ahp, indicated by the @ [read it as 
"null' at the type a_ahp] and an Eq dictionary for that type.

    let {
      ==_ahs :: [a_ahp] -> [a_ahp] -> GHC.Bool.Bool

--Now we pull the comparison function to use out of the dictionary and bind 
it to a local name.

      LclId
      []
      ==_ahs =
        GHC.Classes.== @ [a_ahp] (GHC.Base.$fEq[] @ a_ahp $dEq3_aht) } in

--First, from the Eq dictionary for a_ahp, we pull out the Eq dictionary 
for the type [a_ahp] and from that we choose the "==" function.

    \ (xs_adh :: [a_ahp]) -> ==_ahs xs_adh (GHC.Types.[] @ a_ahp)

--And now we come to the point what happens when the thing is called.
Given an argument xs_adh of type [a_ahp], it applies the comparison 
function pulled out of the dictionary(ies) to a) that argument and b) [] 
(applied to the type a_ahp, so as the value [] :: [a_ahp]).

>
> test =
>    let x = [ ]
>    in tail [1]  == x && tail ['a']  == x

And here (caution, it's long and complicated, the core you get with 
optimisations is much better),


$dEq_riE :: GHC.Classes.Eq [GHC.Types.Char]
GblId
[]
$dEq_riE = GHC.Base.$fEq[] @ GHC.Types.Char GHC.Base.$fEqChar

-- The Eq dictionary for [Char], pulled from the Eq dictionary for Char

$dEq1_riG :: GHC.Classes.Eq GHC.Integer.Type.Integer
GblId
[]
$dEq1_riG =
  GHC.Num.$p1Num @ GHC.Integer.Type.Integer GHC.Num.$fNumInteger

-- The Eq dictionary for Integer, pulled from the Num dictionary for 
Integer (Eq is a superclass of Num, so the Num dictionary contains [a 
reference to] the Eq dictionary)

$dEq2_riI :: GHC.Classes.Eq [GHC.Integer.Type.Integer]
GblId
[]
$dEq2_riI = GHC.Base.$fEq[] @ GHC.Integer.Type.Integer $dEq1_riG

-- The Eq dictionary for [Integer] pulled from the Eq dictionary for 
Integer

Null.test :: GHC.Bool.Bool
GblId
[]
Null.test =
  GHC.Classes.&&
    (GHC.Classes.==
       @ [GHC.Integer.Type.Integer]
       $dEq2_riI

-- pull the "==" member from the Eq dictionary for [Integer]

       (GHC.List.tail
          @ GHC.Integer.Type.Integer

-- apply tail to a list of Integers

          (GHC.Types.:
             @ GHC.Integer.Type.Integer

-- cons (:) an Integer to a list of Integers

             (GHC.Integer.smallInteger 1)

-- 1

             (GHC.Types.[] @ GHC.Integer.Type.Integer)))

-- empty list of integers, first arg of == complete.

       (GHC.Types.[] @ GHC.Integer.Type.Integer))

-- empty list of Integers, second arg of ==, completes first arg of &&

    (GHC.Classes.==
       @ [GHC.Types.Char]
       $dEq_riE

-- pull the == function from the Eq dictionary for [Char]

       (GHC.List.tail
          @ GHC.Types.Char

-- apply tail to a list of Chars

          (GHC.Types.:
             @ GHC.Types.Char

-- cons a Char to a list of Chars

             (GHC.Types.C# 'a')

-- 'a'

             (GHC.Types.[] @ GHC.Types.Char)))

-- empty list of Chars, first arg of == complete

       (GHC.Types.[] @ GHC.Types.Char))

-- empty list of Chars, second arg of ==, completes second arg of &&


When compiled with optimisations, a lot of the stuff is done at compile 
time and we get the more concise core

Null.test :: GHC.Bool.Bool
GblId
[Str: DmdType]
Null.test =
  case GHC.Base.$fEq[]_==
         @ GHC.Integer.Type.Integer
         GHC.Num.$fEqInteger
         (GHC.Types.[] @ GHC.Integer.Type.Integer)
         (GHC.Types.[] @ GHC.Integer.Type.Integer)
  of _ {
    GHC.Bool.False -> GHC.Bool.False;
    GHC.Bool.True ->
      GHC.Base.eqString
        (GHC.Types.[] @ GHC.Types.Char) (GHC.Types.[] @ GHC.Types.Char)
  }


The tails are computed at compile time and the relevant dictionaries are no 
longer looked up in the global instances table but are directly referenced.


>
> (I know I can define null' differently. I'm defining it this way so that
> I can ask this question.)
>
> When I execute test I get True.
>  > test
>  True
>
> So my question is: what is x after compilation? Is it really a thing of
> type
>
>      (Eq a) => [a] ?

During compilation, the types at which x is used are determined (for the 
first list, the overloaded type of 1 :: Num a => a is defaulted to Integer, 
hence we use [] as an empty list of Integers, the second type is explicit) 
and the (hidden, not present at source level) type argument is filled in, 
yielding a value of fixed type. x is used at two different types, so we get 
two different (at Core level) values.

Since x is local to test, x doesn't exist after compilation.
It would still exist if it was defined at the module's top level and was 
exported.

> If so, how should I think of such a thing being stored so that it can be
> found equal to both tail [1] and tail ['a']?

Perhaps it's best to think of a polymorphic expression as a function taking 
types (one or more) as arguments and returning a value (of some type 
determined by its type arguments; that value can still be a function taking 
type arguments if fewer type arguments are provided than the expression 
takes).

> Furthermore, this seems to
> show that (==) is not transitive

At any specific type, (==) is (at least it should be) transitive, but you 
can't compare values of different types.

> since one can't even compile
>   tail [1] == tail ['a']

Type error, of course, on the right, you have a value of type [Char], on 
the left one of Type Num n => [n].
If you povide a Num instance for Char, it will complie and work.

> much less find them to be equal. Yet they are each == to x.

Yes, x can have many types, it's polymorphic.

>
> -- Russ



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

Message: 3
Date: Sat, 2 Oct 2010 16:12:00 +0200
From: Daniel Fischer <[email protected]>
Subject: Re: [Haskell-beginners] fromIntegral
To: [email protected]
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain;  charset="utf-8"

On Saturday 02 October 2010 07:40:19, Russ Abbott wrote:
> I can even write
>
> test =
>    let x = []
>        y = 1 : x
>        z = 'a' : x
>    in ...
>
> But clearly I can't write tail y == tail z.  Does that imply that type
> inferencing prevents one from writing a True expression?

Since it's not a well typed expression (unless there's a Num instance for 
Char in scope, in which case it would work), it doesn't have a value, in 
particular it's not a True expression.

Haskell allows you only to write well typed expressions.



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

Message: 4
Date: Sat, 2 Oct 2010 16:28:12 +0200
From: Daniel Fischer <[email protected]>
Subject: Re: [Haskell-beginners] Re: Beginners Digest, Vol 28, Issue 5
To: [email protected]
Cc: C Gosch <[email protected]>
Message-ID: <[email protected]>
Content-Type: text/plain;  charset="utf-8"

On Saturday 02 October 2010 12:14:44, C Gosch wrote:
> I could be wrong, as I am also new to Haskell.

One can also be wrong with lots of experience ;)

> I suppose
> the compiler simply cannot decide which type the lists you want to
> compare are
> (their constituent elements  must be instances of class Eq, but more is
> not known).

Right, that's exactly the problem. In

null' []

the empty list's type is inferred as

[] :: Eq a => [a]

and no further information is available. Under some common circumstances, 
such ambiguous types are resolved by defaulting, cf.
http://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-790004.3.4
but one of the conditions for defaulting is that a numeric class is 
involved. There's no numeric class involved here, so there's no defaulting.

You can make it compile via the ExtendedDefaultRules language extension, 
then ambiguous type variables with an Eq constraint are defaulted to ().

> Adding type signatures will help the compiler (it should say so as well,
> check the
> error messages):
>
> testNull = ([]::[Int]) == ([]::[Int])

Adding one signature is enough, then the type of the other empty list can 
be inferred.

>
> although I don't know why you would want to do such a thing (sorry I did
> not follow the whole thread).

It's about how polymorphism works (type class polymorphism/overloading in 
particular).

>
> Cheers
> Christian



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

_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners


End of Beginners Digest, Vol 28, Issue 7
****************************************

Reply via email to