7

假设一个函数“获取”一个信息序列(例如一个字符列表),并且应该从中创建不同的类型,其中它的类型取决于表示内容的输入序列 - 并假设类型已经给出。

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

有没有更优雅的方式?

泛型编程会有帮助吗?

它会是什么样子?

4

1 回答 1

8

您的 sum 类型方法对我来说似乎是正确的方法。

举个例子:

  • JSON 文档的第一个字符决定了一个类型——{对于对象、[对于列表、"对于字符串等aeson,一个流行的 Haskell JSON 解析器使用一个 sum 类型来表示其中的每一个。
  • 解析 CBOR 涉及几乎相同的情况。cborg使用sum 类型来捕获所有可能性。
  • 智能游戏格式可以代表各种游戏的移动记录。存储移动所需的信息类型因游戏而异。该sgf库使用sum 类型来捕获可能性。

...等等。

于 2021-05-28T19:02:45.963 回答