I don't understand why I can't construct a list that looks like [1,"1",1.1]
in haskell. I don't think it's static typing that gets in the way because I thought that head
would now have an ill defined type but then I thought about it and there is no reason the run-time system doesn't开发者_运维技巧 instantiate a different version of head
whenever a list is fed into it so head [1,"1",1.1]
would be typed as List->Int
and head (tail [1,"1",1.1])
would be typed as List->String
. Since the run-time already does a lot of bookkeeping why doesn't it provide fancier polymorphic (or is it generic) versions of the various prelude functions? What am I missing here?
It is indeed the typing that prevents this. Consider the definition of a list (notice the type parameter a
, which is missing from your types):
data List a = Nil | Cons a (List a)
In the Cons a (List a)
you can see that the type of thing at the head of the list must be the same type as the elements that follow it. To answer your question, you're not missing a lot: as you say the runtime could do it, but in Haskell you want to make these typing decisions at compile-time, not runtime.
If you want heterogeneous lists, you can see some wizardry by Oleg Kiselyov in his work on HList (= Heterogeneous List). It may not be exactly what you want, but it's in the same rough direction.
Because in Haskell all types are known at compile-time. There's no such thing as waiting until runtime to see what the type will be. And because this is sufficient to do anything you could want to do in a dynamically-typed system, while being easier to reason about to boot.
Just so you know, there actually is a package for heterogeneous lists, using non-trivial techniques and you really should make sure you understand the type system well before diving into this. You don't have this by default because of the type system. A list in Haskell isn't just a list. It's a list of a's, 'a' being Int, String, whatever you want. BUT, one list can contain only one type of values.
Note that you can define "heterogeneous lists" of elements satisfying some constraints using existential quantification, but I think you're not there yet and really should focus on understanding the other answers here before going any further.
There is a heteregenous list type called HList (available on Hackage), but note that there probably is a type for the contents of your list. Consider something like this:
history = [-12, "STATEMENT END", (-244, time January 4 2010), ...]
Your data has a type struggling to emerge, e.g.:
data HistoryEntry = Withdrawal Int | StatementClosing | ScheduledPayment Int CalendarTime
history = [Withdrawal 12, StatementClosing, ScheduledPayment 244 (time January 4 2010)]
In many cases, your data has a type that you just need to seek out.
Look at Heterogenous collections
{-# OPTIONS -fglasgow-exts #-}
--
-- An existential type encapsulating types that can be Shown
-- The interface to the type is held in the show method dictionary
--
-- Create your own typeclass for packing up other interfaces
--
data Showable = forall a . Show a => MkShowable a
--
-- And a nice existential builder
--
pack :: Show a => a -> Showable
pack = MkShowable
--
-- A heteoregenous list of Showable values
--
hlist :: [Showable]
hlist = [ pack 3
, pack 'x'
, pack pi
, pack "string"
, pack (Just ()) ]
--
-- The only thing we can do to Showable values is show them
--
main :: IO ()
main = print $ map f hlist
where
f (MkShowable a) = show a
{-
*Main> main
["3","'x'","3.141592653589793","\"string\"","Just ()"]
-}
精彩评论