有没有另外一种方法来写这样的东西:
data Message = Message1 Int Int ByteString
| Message2 Double Int Int
| Message3 Double Double
.....
| Message256 CustomType
有太多的构造函数,并且很难使用记录语法。我真正想要做的是编写一个解析器,是否有一些替代方法呢?
parse :: Bytestring -> Parser Message
答案 0 :(得分:2)
首先,有一个Plan来实现Haskell的重载记录字段,这将允许在不同的记录中使用相同的名称,并且您只需要在其中的情况下明确指定您想要的那个编译器无法自行解决。
有人说......
我发现处理此问题的最可靠和最方便的方法是每种消息类型一个Haskell类型。
你会:
data Message1 = Message1 Int Int ByteString -- can use records here
data Message2 = Message2 Double Int Int
data Message3 = Message3 { m3_a :: Double, m3_b :: Double }
-- .....
data Message256 = Message256 CustomType
-- A sum type over all possible message types:
data AnyMessage = M1 Message1
| M2 Message2
| M3 Message3
-- ...
| M256 Message256
这样做的好处包括:
它比跨构造函数共享记录更安全:
data T = A { field :: Int }
| B { field :: Int }
| C { bla :: Double } -- no field record
print (field (C 2.3)) -- will crash at runtime, no compiler warning
您现在可以编写仅适用于某些消息类型的函数。
处理此问题的代码仍然非常优雅:
process :: AnyMessage -> IO ()
process anyMsg = case anyMsg of
M1 (Message1 x y bs) -> ...
...
M3 Message3{ m3_a, m3_b } -> ... -- using NamedFieldPuns
我在制作中多次使用过这种模式,它会产生非常强大的代码。