为什么 haskell 没有异构列表

发布于 2024-10-10 13:19:57 字数 376 浏览 3 评论 0原文

我不明白为什么我无法在 haskell 中构造一个类似于 [1,"1",1.1] 的列表。我不认为静态类型会妨碍我,因为我认为 head 现在会有一个定义错误的类型,但后来我想了想,运行时系统没有理由不这么做。每当将列表输入其中时,t 都会实例化不同版本的 head,因此 head [1,"1",1.1] 将被键入为 List->; Inthead (tail [1,"1",1.1]) 将被键入为 List->String。既然运行时已经做了很多簿记工作,为什么它不提供各种前奏函数的更高级的多态(或者通用)版本呢?我在这里缺少什么?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

坏尐絯 2024-10-17 13:19:57

确实是打字阻止了这种情况。考虑列表的定义(注意类型参数 a,它在您的类型中缺失):

data List a = Nil | Cons a (List a)

Cons a (List a) 中,您可以看到列表头部的元素必须与其后面的元素具有相同的类型。为了回答你的问题,你并没有错过很多:正如你所说,运行时可以做到这一点,但在 Haskell 中,你希望在编译时而不是运行时做出这些类型决定。

如果您想要异构列表,您可以在 Oleg Kiselyov 的作品中看到一些魔法 HList(= 异构列表)。它可能不完全是您想要的,但大致方向相同。

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.

╰ゝ天使的微笑 2024-10-17 13:19:57

因为在 Haskell 中,所有类型在编译时都是已知的。不存在需要等到运行时才能查看类型的情况。因为这足以完成您在动态类型系统中想做的任何事情,同时更容易推理启动。

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.

翻身的咸鱼 2024-10-17 13:19:57

正如您所知,实际上有一个用于异构列表的包,使用了不平凡的技术,您确实应该确保在深入研究之前很好地理解类型系统。由于类型系统的原因,默认情况下你没有这个。 Haskell 中的列表不仅仅是一个列表。它是a 的列表,'a' 可以是Int、String,无论你想要什么。但是,一个列表只能包含一种类型的值。

请注意,您可以使用存在量化来定义满足某些约束的元素的“异构列表”,但我认为您还没有做到这一点,并且在进一步讨论之前确实应该专注于理解此处的其他答案。

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.

神爱温柔 2024-10-17 13:19:57

有一种称为 HList 的异构列表类型(可在 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)]

在许多情况下,您的数据有一种您只需要寻找的类型。

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.

黄昏下泛黄的笔记 2024-10-17 13:19:57

查看异构集合

{-# 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 ()"]

-}

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 ()"]

-}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文