初始化记录语法数据类型列表

发布于 2024-12-09 01:27:30 字数 497 浏览 0 评论 0原文

我可以用这种漂亮的方式初始化 Int 列表:

[2, 4 .. 20]

我只是想知道是否有任何方法可以以这种方式初始化我的数据类型列表。像这样,但使用更多的 haskell 方式:

data SieveElement = SieveElement { index :: Int,
                                   flag ::  Bool 
                                   } deriving (Show)

prepareSieve start end step
             | start > end = []
             | otherwise = [SieveElement start True] ++ (prepareSieve (start + step) end step)

let s = prepareSieve 2 20 2

I can initialize the list of Int such beautiful way:

[2, 4 .. 20]

And I am just wondering if there is any to initialize the list of my datatype in such manner. Something like this, but using more haskell way:

data SieveElement = SieveElement { index :: Int,
                                   flag ::  Bool 
                                   } deriving (Show)

prepareSieve start end step
             | start > end = []
             | otherwise = [SieveElement start True] ++ (prepareSieve (start + step) end step)

let s = prepareSieve 2 20 2

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

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

发布评论

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

评论(2

靑春怀旧 2024-12-16 01:27:30

使用列表推导式如何:

[SieveElement i True | i <- [2, 4 .. 20]]

How about using list comprehensions:

[SieveElement i True | i <- [2, 4 .. 20]]
云仙小弟 2024-12-16 01:27:30

虽然Sjoerd的答案是正确的方法去寻找你的代码,我觉得值得指出的是,好的列表范围语法不仅仅适用于 Int 。作为 实例的任何数据类型Enum 可以以相同的方式在列表中使用:

  • [a..] 被翻译为 enumFrom a
  • [a,b..] 被翻译为 enumFromThen a b
  • [a..c] 被翻译为 enumFromTo a c,并且
  • [a,b..c] 被翻译为 enumFromThenTo ab c

不过,这对于您的示例并没有真正起作用,因为我不知道有什么好方法可以为您的类型声明这样的实例。例如,您似乎想要 succ (SieveElement if) = SieveElement (succ i) f(忽略该标志),但不清楚如何实现 toEnum :: Int -> a 和 fromEnum :: a -> Int 以这样的方式,您可以构造所有 SieveElements,同时具有 TrueFalse 标志。


编辑:正如 newacct 在评论中指出的那样,不需要 toEnum 覆盖整个范围:考虑 FloatDouble< /code>,其中 toEnum 仅生成整数。再举一个例子,fromEnum (pi::Double) == (3::Int)。因此,您可以定义 Enum 的实例。然而,天真地这样做是行不通的:

data SieveElement = SieveElement { index :: Int
                                 , flag  :: Bool }
                  deriving (Show)

-- Warning: broken!
instance Enum SieveElement where
  succ (SieveElement i f) = SieveElement (succ i) f
  pred (SieveElement i f) = SieveElement (pred i) f
  toEnum i = SieveElement i False -- or True
  fromEnum (SieveElement i _) = i

这对 enumFrom* 系列方法有一些不好的行为:

*Main> [SieveElement 2 True .. SieveElement 3 True]
[SieveElement {index = 2, flag = False},SieveElement {index = 3, flag = False}]

不幸的是,因为 默认 enumFrom* 实现 fromEnum/toEnum,你将失去你的标志。当然,您可以重新实现这些,但我不确定您想要什么语义,例如 [SieveElement 2 True, SieveElement 4 False .. SieveElement 10 True]。总的来说,这些是我认为

While Sjoerd's answer is the right way to go for your code, I felt it was worth pointing out that the nice list range syntax is available for more than just Ints. Any data type which is an instance of Enum can be used in lists in the same way:

  • [a..] is translated as enumFrom a,
  • [a,b..] is translated as enumFromThen a b,
  • [a..c] is translated as enumFromTo a c, and
  • [a,b..c] is translated as enumFromThenTo a b c.

This doesn't really work for your example, though, since I don't know that there's a good way to declare such an instance for your type. For instance, it seems that you want succ (SieveElement i f) = SieveElement (succ i) f—ignoring the flag—but then it's not clear how you implement toEnum :: Int -> a and fromEnum :: a -> Int in such a way that you can construct all of the SieveElements, with both True and False flags.


Edit: As newacct pointed out in the comments, there's no need for toEnum to cover the entire range: consider Float and Double, for which toEnum produces only whole numbers. As another example, fromEnum (pi :: Double) == (3 :: Int). So you could define an instance of Enum. However, doing this naïvely won't work:

data SieveElement = SieveElement { index :: Int
                                 , flag  :: Bool }
                  deriving (Show)

-- Warning: broken!
instance Enum SieveElement where
  succ (SieveElement i f) = SieveElement (succ i) f
  pred (SieveElement i f) = SieveElement (pred i) f
  toEnum i = SieveElement i False -- or True
  fromEnum (SieveElement i _) = i

This has some bad behavior with the enumFrom* family of methods:

*Main> [SieveElement 2 True .. SieveElement 3 True]
[SieveElement {index = 2, flag = False},SieveElement {index = 3, flag = False}]

Unfortunately, since the default enumFrom* implementations are in terms of fromEnum/toEnum, you'll lose your flag. You could reimplement these, of course, but I'm not sure what semantics you would want for something like [SieveElement 2 True, SieveElement 4 False .. SieveElement 10 True]. In general, these are some more, better, reasons why I think Sjoerd's answer is absolutely the right way to go.

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