Just want to make sure I understand. There does not exist a Haskell implementation-specific extension which provides the sort of dynamic type that would allow one to discriminate at run time between built-in types; right? eg, main=do object<-readLn case object of --or some such syntax ()->putStrLn "void type detected" (a::Integer)->putStrLn "Integer type detected" For those readers whose prelude is rusty, I quote from the prelude: readLn :: Read a => IO a readLn = do l <- getLine r <- readIO l return r And even if the object being discriminated "lacks polymorphicity", eg, this next, that does not change the answer to my question; right? main=do command<-readLn let object=case command of "Integer"->(5::Integer) "Void"->() case object of ()->putStrLn "void type detected" (a::Integer)->putStrLn "Integer type detected"
You are correct. You can't say: let x = if ??? then () else (5::Integer) because then the compiler can't assign a type to x. However, to achieve what you want, you might try something like this (untested code follows):
main = do l <- getLine let x = case maybeRead l of Just () -> Left () _ -> case maybeRead l of Just (i::Integer) -> Right i if isLeft x then putStrLn "Unit type detected" else putStrLn "Integer type detected"
where
maybeRead :: Read a => String -> Maybe a maybeRead x = case readsPrec x of [(a,_)] -> Just a _ -> Nothing
or something like that. Another way to do it would be to define a "universal" type:
data Univ = UUnit () | UInteger Integer | UDouble Double | ...
and define an instance of read on it that loos like the cascaded cases from above... HTH, Hal -- Hal Daume III "Computer science is no more about computers | hdaume@isi.edu than astronomy is about telescopes." -Dijkstra | www.isi.edu/~hdaume On Tue, 7 Jan 2003, Richard Uhtenwoldt wrote:
Just want to make sure I understand.
There does not exist a Haskell implementation-specific extension which provides the sort of dynamic type that would allow one to discriminate at run time between built-in types; right? eg,
main=do object<-readLn case object of --or some such syntax ()->putStrLn "void type detected" (a::Integer)->putStrLn "Integer type detected"
For those readers whose prelude is rusty, I quote from the prelude:
readLn :: Read a => IO a readLn = do l <- getLine r <- readIO l return r
And even if the object being discriminated "lacks polymorphicity", eg, this next, that does not change the answer to my question; right?
main=do command<-readLn let object=case command of "Integer"->(5::Integer) "Void"->() case object of ()->putStrLn "void type detected" (a::Integer)->putStrLn "Integer type detected" _______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
On Wed, 8 Jan 2003 07:19 am, Hal Daume III wrote:
Another way to do it would be to define a "universal" type:
data Univ = UUnit () | UInteger Integer | UDouble Double | ...
I'm fairly new to Haskell, but worked on Mercury until recently. Mercury has a type "univ" which might be declared something like: data Univ = Univ a (I don't know the correct syntax for existentially quantified types in haskell, but the intent of the declaration is that the monomorphic type Univ has a single constructor is a value of existentially quantified type) The library then has functions that do the equivalent of mkUniv :: a -> Univ and getValue :: Univ -> Maybe a The interesting bit is getValue. In implementation terms, what it does is compare the dictionary stored in the Univ value (values containing existentially quantified components also contain the dictionary for the existentially quantified type variables) with the one that is implicitly passed in for the result type. As it happens, almost all of this can be done in Mercury using some of the reflection libraries. I believe (nth hand) that something similar has been done in haskell, but my understanding is that it isn't in the standard library. Tom -- Dr Thomas Conway Multimedia Database Systems, RMIT University <conway@mds.rmit.edu.au> 499 User error! Replace user, and press any key.
I'm fairly new to Haskell, but worked on Mercury until recently. Mercury has a type "univ" which might be declared something like:
you would write this: data Univ = forall a . Univ a
mkUniv :: a -> Univ
right, 'mkUniv = Univ' is sufficient.
getValue :: Univ -> Maybe a
yes, this is the interesting bit :). you could presumably use dynamics to simulate this, but you'd have to do a bit of work and you wouldn't have as general a type signature. you could do something like
import Data.Dynamic
data Univ = Univ Dynamic
mkUniv :: Typeable a => a -> Univ mkUniv = Univ . toDyn
getValue :: Typeable a => Univ -> Maybe a getValue (Univ d) = fromDynamic d
then you can do something like: *Foo> getValue (mkUniv 'a') :: Maybe Char Just 'a' *Foo> getValue (mkUniv 'a') :: Maybe Int Nothing This works in GHC and Hugs (though for the version of Hugs I have you use just Dynamic instead of Data.Dynamic). Of course, there's no reason to have Univ in this case, you can just use the Dynamic type. - Hal
G'day all. On Wed, Jan 08, 2003 at 08:42:20AM +1100, Thomas Conway wrote:
I'm fairly new to Haskell, but worked on Mercury until recently. Mercury has a type "univ" which might be declared something like:
data Univ = Univ a
The equivalent would be: data Univ = forall a. Univ a
I believe (nth hand) that something similar has been done in haskell, but my understanding is that it isn't in the standard library.
That would be Data.Dynamic: data Dynamic -- abstract toDyn :: (Typeable a) => a -> Dynamic fromDynamic :: (Typeable a) => Dynamic -> Maybe a (There is a certain kind of logic behind the inconsistent naming, incidentally.) The Typeable class basically implements RTTI explicitly: class Typeable a where typeOf :: a -> TypeRep Unfortunately, Typeable can't be derived automatically. Maybe in Haskell 2. For further details, see: http://haskell.org/ghc/docs/latest/html/base/Data.Dynamic.html Cheers, Andrew Bromage
On 08-Jan-2003, Andrew J Bromage <ajb@spamcop.net> wrote:
On Wed, Jan 08, 2003 at 08:42:20AM +1100, Thomas Conway wrote:
Mercury has a type "univ" which might be declared something like:
data Univ = forall a. Univ a
I believe (nth hand) that something similar has been done in haskell, but my understanding is that it isn't in the standard library.
That would be Data.Dynamic:
data Dynamic -- abstract toDyn :: (Typeable a) => a -> Dynamic fromDynamic :: (Typeable a) => Dynamic -> Maybe a ... The Typeable class basically implements RTTI explicitly:
class Typeable a where typeOf :: a -> TypeRep
Unfortunately, Typeable can't be derived automatically.
That's not the only problem. The other problem is that because `Typeable' instances aren't built-in, `fromDynamic' is not type-safe. The implementation of `fromDynamic' calls `typeOf' and then if the types match, it does an unsafe cast. If `typeOf' lies, then `fromDynamic' may break type safety. So it is not safe to allow the use of `fromDynamic' if you are executing untrusted code.
Maybe in Haskell 2.
Yes, it would be nice to have a built-in, type-safe, version of Dynamic in Haskell 2. -- Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
Fergus Henderson wrote:
Maybe in Haskell 2.
Yes, it would be nice to have a built-in, type-safe, version of Dynamic in Haskell 2.
It would also be nice if it were a little less abstract; e.g. either exposing the constructors for Dynamic and TypeRep or providing suitable accessors would be preferable to having to parse the result of "show". -- Glynn Clements <glynn.clements@virgin.net>
Glynn Clements <glynn.clements@virgin.net> wrote,
Fergus Henderson wrote:
Maybe in Haskell 2.
Yes, it would be nice to have a built-in, type-safe, version of Dynamic in Haskell 2.
It would also be nice if it were a little less abstract; e.g. either exposing the constructors for Dynamic and TypeRep or providing suitable accessors would be preferable to having to parse the result of "show".
You may want to have a look at one of the papers from the 2002 Haskell Workshop: http://portal.acm.org/citation.cfm?id=581690.581698&coll=portal&dl=ACM&type=... You can get quite far with H98 + existentials. Cheers, Manuel
G'day all. On Tue, Jan 14, 2003 at 07:13:57PM +1100, Fergus Henderson wrote:
That's not the only problem. The other problem is that because `Typeable' instances aren't built-in, `fromDynamic' is not type-safe. The implementation of `fromDynamic' calls `typeOf' and then if the types match, it does an unsafe cast. If `typeOf' lies, then `fromDynamic' may break type safety.
First, an unsupported assertion: In any declarative language implementation intended to be practical, there will inevitably be a place or two where it is possible to lie to the compiler, thus potentially making it break various language rules. GHC has it here, and also in the "RULES" pragma. Mercury (to pick but one other example) has the "promise" pragma which amounts to the same thing. I surely don't need to quote it again, but I will anyway: "If you lie to your compiler, it will get its revenge." -- Henry Spencer Secondly, you're absolutely right:
Yes, it would be nice to have a built-in, type-safe, version of Dynamic in Haskell 2.
And so is Glynn: | It would also be nice if it were a little less abstract; e.g. either | exposing the constructors for Dynamic and TypeRep or providing | suitable accessors would be preferable to having to parse the result | of "show". What You Really Want(tm) is some kind of controlled reflection and meta-interpretation mechanism which makes it unnecessary for automatically derivable typeclasses like "Show", "Eq", "Enum" and "Typeable" to require special compiler support. Cheers, Andrew Bromage
Hal Daume III writes:
You are correct. You can't say:
let x = if ??? then () else (5::Integer)
I meant to ask if when you do this next let x = if ??? then toDyn () else toDyn (5::Integer) can you then dispatch on x's type. In my sample code, I forgot the toDyns. eek! Anyway, this next line in your post showed me I do not even need Dynamic or any other library. Meets my needs. I feel a little dumb for not thinking of it myself. (Perhaps that's what I like about Haskell: it regularly makes me feel dumb.)
data Univ = UUnit () | UInteger Integer | UDouble Double | ...
Thank you for the info, Hal Daume. P.S. Here's some simple tested code that demonstrates dispatching on the Univ type: data Univ = UUnit () | UInteger Integer | UOther main=do command<-getLine --make an object of Univ type: let object::Univ object=case command of "integer"->UInteger (5::Integer) "unit"->UUnit () _->UOther --now dispatch on it: case object of UUnit ()->putStrLn "void type detected" UInteger (a::Integer)->putStr "Integer type detected, namely ">> print a _->putStrLn "detected a type the programmer doesnt want to bother with" main
participants (7)
-
Andrew J Bromage -
Fergus Henderson -
Glynn Clements -
Hal Daume III -
Manuel M T Chakravarty -
Richard Uhtenwoldt -
Thomas Conway