在Haskell中从未知序列创建不同类型?
假设一个函数“获取”一个信息序列(例如一个字符列表),并且应该从中创建不同的类型,其中它的类型取决于输入序列,它表示内容 - 并假设类型已经给出。
numFromString :: [Char] -> ???
我想有几种可能性。
我的第一个想法是使用类型参数。
main :: IO ()
main =
do
sLine <- getLine
print $ numFromString sLine
numFromString :: (Show a, Read a) => String -> (Maybe a)
numFromString ('I':'n':'t':'e':'g':'e':'r':rs) = Just ((read rs) :: Integer)
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this does not work
numFromString ('I':'n':'t':rs) = Just ((read rs) :: Int)
numFromString _ = Nothing
...但我们不能只提供一个 Integer 类型变量,或者我们可以吗?。
我的第二个想法是使用类型类
main :: IO ()
main =
do
sLine <- getLine
print $ ((numFromString sLine) :: (Maybe Integer))
-- ^^^^^^^^^^^^^^^ I have to decide in advance which type I want to get
class (Show a, Read a) => XClass a where
numFromString :: String -> (Maybe a)
instance XClass Int where
numFromString ('I':'n':'t':rs) = Just ((read rs) :: Int)
numFromString _ = Nothing
instance XClass Integer where
numFromString ('I':'n':'t':'e':'g':'e':'r':rs) = Just ((read rs) :: Integer)
numFromString _ = Nothing
...但这也不起作用,当我们使用 numFromString 时,是吗?
我的第三个想法是使用 sum 类型的数据类型。
main :: IO ()
main =
do
sLine <- getLine
print $ numFromString sLine
data X = XInt Int | XInteger Integer | XNone
deriving Show
numFromString :: String -> X
numFromString ('I':'n':'t':'e':'g':'e':'r':rs) = XInteger (read rs)
numFromString ('I':'n':'t':rs) = XInt (read rs)
numFromString _ = XNone
有没有更优雅的方式?
泛型编程有帮助吗?
它会是什么样子?
回答
您的总和类型方法对我来说是正确的方法。
例如:
- JSON 文档的第一个字符决定了类型——
{对于对象、[对于列表、"字符串等aeson,流行的 Haskell JSON 解析器使用可以表示其中每一个的 sum 类型。 - 解析 CBOR 涉及几乎相同的情况。
cborg使用sum 类型来捕获所有可能性。 - 智能游戏格式可以代表各种游戏的走法记录。存储移动所需的信息类型因游戏而异。该
sgf库使用sum 类型来捕捉可能性。
...等等。