getting the right types
Simon Peyton-Jones
simonpj@microsoft.com
Tue, 5 Nov 2002 11:04:24 -0000
Interesting. You want to control a data type used *inside* an algorithm
from outside. Here's a smaller version:
foo :: String -> String
foo s =3D show (read s)
This is ambiguous; what type should 'read' return? Your idea: pass in
that type via a proxy value:
foo :: (Read a, Show a) =3D> a -> String -> String
foo p s =3D show (read s `asTypeOf` p)
Now you can say
foo (undefined :: Int) "34"
and it'll work. A neater way to do this with GHC is to use scoped type
variables:
foo :: (Read a, Show a) =3D> a -> String -> String
foo (p::a) s =3D show (read s :: a)
One reason this is neater is that it scales up better when you want to
pass a type constructor instead of a type. First define a data type
with no constructors, and a phantom type arg
data Proxy (a :: * -> *)
Now you can write a function like this
f :: (MArray a ix e) =3D> Proxy a -> ....
f (p :: Proxy a) ... =3D do { (arr :: a ix e) <- newArray ...
The type variable 'a' is bound by the (Proxy a) pattern, and scopes over
the body. The
type variables 'ix' and 'e' in the do-binding are bound right there
(since they aren't already in scope).
Another use for phantom types!
Simon
| -----Original Message-----
| From: Hal Daume III [mailto:hdaume@ISI.EDU]
| Sent: 03 November 2002 19:31
| To: Haskell Mailing List
| Subject: getting the right types
|=20
| Hi all,
|=20
| I have a function which essentially looks like this:
|=20
| f my_data =3D do
| a1 <- newArray ...
| ...
| a2 <- newArray ...
| g my_data a1 a2
|=20
| where f is a monadic operation essentially of type 'a -> m a'. The
| problem is that when this function isn't given a type signature, you
get
| something like:
|=20
| f :: (MArray a1 p e, MArray a2 p e) =3D> t
|=20
| where a1 and a2 aren't bound in t. Now, I could provide a type
signature
| on the array expressions, something like:
|=20
| ... (a1 :: IOArray Int Int) <- newArray ...
|=20
| but i would like to be able to use unboxed arrays when possible, and i
| don't want to bind the funtion to be in IO. My current solution is to
| define:
|=20
| data ArrayType arr prob =3D forall ix . ArrayType (arr ix prob)
| asArray :: arr ix prob -> ArrayType arr prob -> arr ix prob
| a `asArray` _ =3D a
|=20
| Sort of like asTypeOf. Then, I change f to:
|=20
| f :: (MArray arr p e) =3D> ArrayType arr p -> t -> m t
| f arr_type ... =3D ...
|=20
| And inside f I have a function:
|=20
| newArray_arr bnds init =3D
| do a <- newArray bnds init
| return (a `asArray` arr_type)
|=20
| This enables me to create arrays of arbitrary representation with the
same
| values but different indices (which is important).
|=20
| However, this strikes me as horribly hackish. Is there some better
way to
| do this?
|=20
| - Hal
|=20
| --
| Hal Daume III
|=20
| "Computer science is no more about computers | hdaume@isi.edu
| than astronomy is about telescopes." -Dijkstra | www.isi.edu/~hdaume
|=20
| _______________________________________________
| Haskell mailing list
| Haskell@haskell.org
| http://www.haskell.org/mailman/listinfo/haskell