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: Help with types (Daniel Carrera)
2. Re: Help with types (Daniel Carrera)
3. Re: Help with types (Jason Dusek)
4. Re: Help with types (Thomas Davie)
5. Re: Help with types (Daniel Fischer)
6. Re: Help with types (Daniel Carrera)
7. Type families with kind * -> * (Marco T?lio Gontijo e Silva)
8. Re: Type families with kind * -> * (Jason Dusek)
9. Re: Type families with kind * -> * (Daniel Fischer)
----------------------------------------------------------------------
Message: 1
Date: Thu, 23 Apr 2009 16:17:44 +0200
From: Daniel Carrera <[email protected]>
Subject: Re: [Haskell-beginners] Help with types
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
aditya siram wrote:
> There is a chapter in Real World Haskell [1] devoted to this exact
> question on this exact piece of code.
>
> hth,
> -deech
>
> [1] http://book.realworldhaskell.org/read/profiling-and-optimization.html
Wow. Indeed, that is the exact same piece of code. Thanks.
Daniel.
------------------------------
Message: 2
Date: Thu, 23 Apr 2009 16:25:25 +0200
From: Daniel Carrera <[email protected]>
Subject: Re: [Haskell-beginners] Help with types
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Thomas Davie wrote:
>> It looks like (/) is happy with Num but doesn't like Int. This
>> surprises me. I would have thought that Fractional is a kind of Num
>> and Int is a kind of Fractional
>
> Int isn't a Fractional because it can't represent fractional numbers.
Sure, but any integer is trivially also a fraction, so I would think
that it would be an acceptable input for (/). On the other hand, if it
is at all possible for a Num to contain something that cannot be
converted to a fraction, then a Num should not be a valid input for (/).
------------------------------
Message: 3
Date: Thu, 23 Apr 2009 07:33:01 -0700
From: Jason Dusek <[email protected]>
Subject: Re: [Haskell-beginners] Help with types
To: Daniel Carrera <[email protected]>
Cc: [email protected]
Message-ID:
<[email protected]>
Content-Type: text/plain; charset=UTF-8
2009/04/23 Daniel Carrera <[email protected]>:
> ...if it is at all possible for a Num to contain something
> that cannot be converted to a fraction, then a Num should not
> be a valid input for (/).
And it isn't.
Prelude> :t (/)
(/) :: forall a. (Fractional a) => a -> a -> a
--
Jason Dusek
------------------------------
Message: 4
Date: Thu, 23 Apr 2009 16:40:49 +0200
From: Thomas Davie <[email protected]>
Subject: Re: [Haskell-beginners] Help with types
To: Daniel Carrera <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=WINDOWS-1252; format=flowed;
delsp=yes
On 23 Apr 2009, at 16:25, Daniel Carrera wrote:
> Thomas Davie wrote:
>>> It looks like (/) is happy with Num but doesn't like Int. This
>>> surprises me. I would have thought that Fractional is a kind of
>>> Num and Int is a kind of Fractional
>> Int isn't a Fractional because it can't represent fractional numbers.
>
> Sure, but any integer is trivially also a fraction, so I would think
> that it would be an acceptable input for (/). On the other hand, if
> it is at all possible for a Num to contain something that cannot be
> converted to a fraction, then a Num should not be a valid input for
> (/).
The problem here is that (/) also *outputs* that type if you can't
represent a fraction, how do you give the result of 1/4?
Bob
------------------------------
Message: 5
Date: Thu, 23 Apr 2009 16:56:37 +0200
From: Daniel Fischer <[email protected]>
Subject: Re: [Haskell-beginners] Help with types
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="iso-8859-1"
Am Donnerstag 23 April 2009 15:52:00 schrieb Daniel Carrera:
> Daniel Fischer wrote:
> > Try explicitly converting the length to the appropriate type:
> >
> > average xs = sum xs / fromIntegral (length xs)
>
> Thanks. Could you help me understand what's happening?
>
> 1. length returns Int.
> 2. sum returns Num.
> 3. (/) wants Fractional.
>
> It looks like (/) is happy with Num but doesn't like Int.
Not quite. (/) needs a type which is an instance of Fractional. All instances
of
Fractional are also instances of Num, so Fractional is more specific than Num.
If you divide the result of sum using (/), sum is used at the less general type
(Fractional a => [a] -> a).
Every function can be used at all types which are less general than its most
general type.
In this case it goes like this:
The type checker sees
average xs = sum xs / fromIntegral (length xs)
so average is a function, having type arg -> result where
xs :: arg
sum xs / fromIntegral (length xs) :: result
Now the right hand side, the expression sum xs / fromIntegral (length xs), is
typed.
(/) has the type Fractional a => a -> a -> a, so from that we can deduce that
sum xs :: Fractional a => a
fromIntegral (length xs) :: Fractional a => a
result = Fractional a => a
, all for the same a.
sum has the type (Num n => [n] -> n), so for the expression sum xs to be well
formed, xs
must have the type (Num n => [n]), and then
sum xs :: Num n => n
Now that type has to be unified with the type deduced for this subexpression
above. Since
the first says whichever type, as long as it's a member of class Fractional and
the second
says whichever type, as long as it's a member of class Num, the unification
yields
"whichever type, as long as it's a member of both, class Fractional and class
Num",
(Fractional a, Num a) => a.
Since Fractional is a subclass of Num, the second condition is implied by the
first and
the type simplifies to Fractional a => a. Since the type of xs' elements is th
same as the
type of sum xs, the Fractional constraint has to be added to the type of xs
too, giving
xs :: Fractional a => [a]
arg = Fractional a => [a]
fromIntegral has type (Integral a, Num b) => a -> b. Since length xs :: Int and
Int is a
member of Integral,
fromIntegral (length xs) :: Num n => n
This has to be unified with the type deduced above, giving
fromIntegral (length xs) :: Fractional a => a
, too. Note that (sum xs) and (fromIntegral (length xs)) have the type
Fractional a => a
*as subexpressions of sum xs / fromIntegral (length xs)*, in isolation, both
would have
the type Num n => n.
Assembling all that, we find
average :: Fractional a => [a] -> a
> This surprises
> me. I would have thought that Fractional is a kind of Num and Int is a
> kind of Fractional,
No, Int is an instance of Integral, which is sort of the opposite of Fractional.
Fractional means that you can freely divide (excluding division by 0 of
course), things
like 3.24 make sense, Integral means that things like mod or gcd make sense.
Though it is possible to make a type an instance of both, Fractional and
Integral, that
doesn't really make sense.
> so a function that expects Fractional would be happy
> with an Int but maybe not with a Num. But clearly that's not the way it
> works.
>
> 'fromIntegral' converts Int to Num. So obviously, Num is good and Int is
> bad.
The thing is that the types are implicitly universally quantified, so the type
of
fromIntegral is really
forall a b. (Integral a, Num b) => a -> b
and the type of
fromIntegral something
is
forall b. Num b => b
> But I don't really get why.
fromIntegral says, whatever Num type you want, I can give it to you. In
particular, if the
caller wants a Double, fromIntegral provides a Double. If the caller wants any
type, as
long as it's a member of Fractional, fromIntegral provides that.
Int is a fixed type, the caller cannot choose which type shall be returned,
it's always
just Int, so the caller can only use operations which are defined on Int. (/)
is not
defined on Int, because the result of dividing two Ints is rarely an Int. For
divisions of
Integral types, there are div and quot (with mod and rem for the remainders).
>
> > will yield a working (albeit inefficient)
> > average :: Fractional a => [a] -> a
>
> Why is it inefficient? How would you make it efficient?
It's inefficient because the list has to be traversed twice, once for the sum
and once for
the length. Also, the whole list is kept in memory between the two traversals,
which is a
very bad thing for long lists.
To make it efficient, calculate the sum and the length together, as in
average xs = loop 0 0 xs
where
loop sm ln [] = sm / fromIntegral ln
loop sm ln (y:ys) = loop (sm+y) (ln+1) ys
although that probably needs strictness annotations on sm and ln to be
efficient
(otherwise, the running sum and length may not be evaluated but build up large
thunks
which are only forced at the end and may cause a stack overflow then).
>
> Thanks for the help.
>
> Cheers,
> Daniel.
------------------------------
Message: 6
Date: Thu, 23 Apr 2009 18:26:02 +0200
From: Daniel Carrera <[email protected]>
Subject: Re: [Haskell-beginners] Help with types
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Daniel Fischer wrote:
> Not quite. (/) needs a type which is an instance of Fractional. All instances
> of
> Fractional are also instances of Num, so Fractional is more specific than Num.
> If you divide the result of sum using (/), sum is used at the less general
> type
> (Fractional a => [a] -> a).
> Every function can be used at all types which are less general than its most
> general type.
Aahh.... I see. The "sum" part is making more sense now.
So let's see: "sum" is a (Num a => [a] -> a). Every function can be used
at all types that are less general than its most general type.
Fractional is a kind of Num. Therefore, "sum" can be used as (Fractional
a => [a] -> a) to make it compatible with (/).
Thanks for the detailed explanation. It's a lot clearer now.
>> This surprises
>> me. I would have thought that Fractional is a kind of Num and Int is a
>> kind of Fractional,
>
> No, Int is an instance of Integral, which is sort of the opposite of
> Fractional.
> Fractional means that you can freely divide (excluding division by 0 of
> course), things
> like 3.24 make sense, Integral means that things like mod or gcd make sense.
> Though it is possible to make a type an instance of both, Fractional and
> Integral, that
> doesn't really make sense.
This helps. I think I see the problem:
Suppose that Integral was a kind of Fractional, the way I proposed. What
happens when someone writes (x / y) `mod` z ? Trying to apply the same
reasoning you used above:
(/) :: Fractional a => a -> a -> a
mod :: Integral a => a -> a -> a
Using the logic that you explained above, we would have to force (/) to
give an Integral result, which in general is wrong. And that is a
reasonable argument why Integral should not be an instance of Fractional.
Am I right more or less?
>> But I don't really get why.
>
> fromIntegral says, whatever Num type you want, I can give it to you.
... and 'length' says, "whatever Int type you want, I can give it to
you", but (/) says "I don't want an Int, I want a Fractional" and that's
why 'length' alone doesn't get along with (/).
I'm beginning to see the reasoning behind Haskell's behaviour, but I
think I'll need time to get used to it.
Thanks for the help.
Daniel.
------------------------------
Message: 7
Date: Thu, 23 Apr 2009 14:15:05 -0300
From: Marco T?lio Gontijo e Silva <[email protected]>
Subject: [Haskell-beginners] Type families with kind * -> *
To: [email protected]
Message-ID: <1240506905.5271.60.ca...@zezinho>
Content-Type: text/plain
Hello,
I read the type families example at
http://haskell.org/haskellwiki/GHC/Indexed_types and I wanted to do
something similar to the Collects example, but using a type of kind * ->
*:
> class StateFunctor sf where
> type SFMonad sf
> type SFValue sf
> sfmap :: (SFValue sf -> SFValue sf) -> sf -> SFMonad sf ()
I wrote the instance as:
> instance StateFunctor (ListStore a) where
> type SFMonad (ListStore a) = IO
> type SFValue (ListStore a) = a
> sfmap function listStore
> = listStoreGetSize listStore >>= listStoreSfmap function listStore
> listStoreSfmap :: (a -> a) -> ListStore a -> Int -> IO ()
> listStoreSfmap _function _listStore 0 = []
> listStoreSfmap function listStore size
> = listStoreGetValue listStore index
> >>= listStoreSetValue listStore index . function
> >> listStoreSfmap function listStore index
> where
> index :: Int
> index = pred size
I'm getting:
DistroCreator/GUI/List.hs:51:47:
Kind error: `SFMonad' is applied to too many type arguments
In the type `SFMonad sf ()'
In the type `sf -> SFMonad sf ()'
In the type `(SFValue sf -> SFValue sf) -> sf -> SFMonad sf ()'
Failed, modules loaded: none.
How can I use type families with types * -> *?
Greetings.
--
marcot
http://marcot.iaaeee.org/
------------------------------
Message: 8
Date: Thu, 23 Apr 2009 10:27:00 -0700
From: Jason Dusek <[email protected]>
Subject: Re: [Haskell-beginners] Type families with kind * -> *
To: Marco T?lio Gontijo e Silva <[email protected]>
Cc: [email protected]
Message-ID:
<[email protected]>
Content-Type: text/plain; charset=UTF-8
class StateFunctor sf where
 type SFMonad sf :: * -> *
 type SFValue sf
 sfmap :: (SFValue sf -> SFValue sf) -> sf -> SFMonad sf ()
------------------------------
Message: 9
Date: Thu, 23 Apr 2009 19:32:15 +0200
From: Daniel Fischer <[email protected]>
Subject: Re: [Haskell-beginners] Type families with kind * -> *
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="iso-8859-15"
Am Donnerstag 23 April 2009 19:15:05 schrieb Marco Túlio Gontijo e Silva:
> Hello,
>
> I read the type families example at
> http://haskell.org/haskellwiki/GHC/Indexed_types and I wanted to do
> something similar to the Collects example, but using a type of kind * ->
>
> *:
> > class StateFunctor sf where
> > type SFMonad sf
> > type SFValue sf
> > sfmap :: (SFValue sf -> SFValue sf) -> sf -> SFMonad sf ()
>
> I wrote the instance as:
> > instance StateFunctor (ListStore a) where
> > type SFMonad (ListStore a) = IO
> > type SFValue (ListStore a) = a
> > sfmap function listStore
> > = listStoreGetSize listStore >>= listStoreSfmap function listStore
> >
> > listStoreSfmap :: (a -> a) -> ListStore a -> Int -> IO ()
> > listStoreSfmap _function _listStore 0 = []
> > listStoreSfmap function listStore size
> > = listStoreGetValue listStore index
> >
> > >>= listStoreSetValue listStore index . function
> > >>
> > >> listStoreSfmap function listStore index
> >
> > where
> > index :: Int
> > index = pred size
>
> I'm getting:
>
> DistroCreator/GUI/List.hs:51:47:
> Kind error: `SFMonad' is applied to too many type arguments
> In the type `SFMonad sf ()'
> In the type `sf -> SFMonad sf ()'
> In the type `(SFValue sf -> SFValue sf) -> sf -> SFMonad sf ()'
> Failed, modules loaded: none.
>
> How can I use type families with types * -> *?
For example:
-----------------------------------
{-# LANGUAGE TypeFamilies, KindSignatures #-}
module TypeF where
data ListStore a = Dummy
listStoreGetSize = undefined
listStoreSfmap = undefined
class StateFunctor sf where
type SFMonad sf :: (* -> *)
type SFValue sf
sfmap :: (SFValue sf -> SFValue sf) -> sf -> SFMonad sf ()
instance StateFunctor (ListStore a) where
type SFMonad (ListStore a) = IO
type SFValue (ListStore a) = a
sfmap function listStore
= listStoreGetSize listStore >>= listStoreSfmap function listStore
-------------------------------------
Prelude> :l TypeF
[1 of 1] Compiling TypeF ( TypeF.hs, interpreted )
Ok, modules loaded: TypeF.
>
> Greetings.
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 10, Issue 25
*****************************************