我不明白为什么我不能在haskell中构建一个看起来像[1,"1",1.1]
的列表。我认为静态类型不会妨碍我,因为我认为head
现在会有一个定义不合适的类型,但后来我想到了它并且运行时系统没有理由不实例化每当列表被输入时head
的不同版本,因此head [1,"1",1.1]
将被输入为List->Int
而head (tail [1,"1",1.1])
将被输入为List->String
。由于运行时已经进行了大量的簿记,为什么它不提供各种前奏函数的更好的多态(或它是通用的)版本?我在这里缺少什么?
答案 0 :(得分:16)
这确实是打字阻止了这一点。考虑列表的定义(注意类型参数a
,类型中缺少这个参数:
data List a = Nil | Cons a (List a)
在Cons a (List a)
中,您可以看到列表头部的事物类型必须与其后面的元素的类型相同。要回答你的问题,你不会错过很多:正如你所说运行时可以做到的那样,但是在Haskell中你想在编译时做出这些打字决定,而不是运行时。
如果你想要异构列表,你可以看到Oleg Kiselyov在HList(=异构列表)上的工作中的一些魔法。它可能不是你想要的,但它是在同一个粗略的方向。
答案 1 :(得分:3)
因为在Haskell中所有类型在编译时都是已知的。没有等到运行时才能看到类型的东西。而且因为这足以在动态类型的系统中做任何你想做的事情,同时更容易推理启动。
答案 2 :(得分:3)
就是你知道,实际上有一个异构列表的包,使用非平凡的技术,你真的应该确保你在进入这个之前很好地理解类型系统。由于类型系统,默认情况下没有此功能。 Haskell中的列表不仅仅是一个列表。它是的列表,'a'是Int,String,无论你想要什么。但是,一个列表只能包含一种类型的值。
请注意,您可以使用存在量化来定义满足某些约束的元素的“异构列表”,但我认为您还没有,并且在继续进行之前应该专注于理解其他答案。
答案 3 :(得分:3)
有一个名为HList的heteregenous列表类型(在Hackage上可用),但请注意,列表的内容可能有一个类型。考虑这样的事情:
history = [-12, "STATEMENT END", (-244, time January 4 2010), ...]
您的数据有一种难以出现的类型,例如:
data HistoryEntry = Withdrawal Int | StatementClosing | ScheduledPayment Int CalendarTime
history = [Withdrawal 12, StatementClosing, ScheduledPayment 244 (time January 4 2010)]
在许多情况下,您的数据类型只需要查找。
答案 4 :(得分:3)
{-# 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 ()"]
-}