开发者

Initialize the List of Record Syntax Data Type

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


How about using list comprehensions:

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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜