我试图更多地了解 Haskell,并成功地遵循了 Aeson 的例子。我现在正在尝试适应它,但我缺乏并且我确信这是一个相当基本的理解。如果重要的话,我正在使用 IHaskell-aeson 包在 Jupyter Lab 设置中执行此操作。
初始示例假设输入 JSON 文件由单个简单对象组成。输出解析对象并提供一个小的 greet
信息。
{
"name": "Johann Carl Freidrich Guass",
"nationality": "German",
"born": "30 April 1777",
"died": "23 February 1855"
}
输出:Johann Carl Freidrich Guass was born 30 April 1777
我想扩展它以使用此 JSON:{
"mathematicians": [
{ "name".... },
{ "name".... },
{ "name".... },
{ "name".... }
]
}
这是我现在的代码,我在第一个版本中留下了评论(:extension
用于 IHaskell/Jupyter)::extension OverloadedStrings
import qualified Data.ByteString.Lazy as B
import Control.Monad (mzero)
import Data.Foldable (toList)
import Data.Aeson.Types (Parser)
data Mathematicians = Mathematicians
{ mathematicians :: [Mathematician]
} deriving (Show)
data Mathematician = Mathematician
{ name :: String
, nationality :: String
, born :: String
, died :: Maybe String
} deriving (Show)
instance A.FromJSON Mathematician where
parseJSON (A.Object v) = Mathematician
<$> (v A..: "name")
<*> (v A..: "nationality")
<*> (v A..: "born")
<*> (v A..:? "died")
parseJSON _ = mzero
instance A.FromJSON Mathematicians where
parseJSON (A.Object v) = do
ms <- v A..: "mathematicians"
fmap Mathematicians $ A.parseJSON ms
parseJSON _ = mzero
input <- B.readFile "mathematicians.json"
greet m = (show.name) m ++
" was born " ++
(show.born) m
-- let mm = A.decode input :: Maybe Mathematician
-- case mm of
-- Nothing -> print "error parsing JSON"
-- Just m -> (putStrLn.greet) m
let mms = A.decode input :: Maybe Mathematicians
case mms of
Nothing -> print "error parsing JSON"
Just ms -> print ms
打印ms
给了我以下内容,这让我相信解析可能正在工作:Mathematicians {mathematicians = [Mathematician {name = "Johann Carl Friedrich Gauss", nationality = "German", born = "30 April 1777", died = Just "23 February 1855"},Mathematician {name = "Leonhard Euler", nationality = "German", born = "15 April 1707", died = Just "18 September 1783"},Mathematician {name = "William Rowan Hamilton", nationality = "Irish", born = "3 August 1805", died = Just "2 September 1865"},Mathematician {name = "Terence Chi-Shen Tao", nationality = "Australia", born = "17 July 1975", died = Nothing}]}
此外,故意在
Mathematician
中插入一个错字解析器导致 error parsing JSON
消息,所以手指交叉它似乎解析工作。但是,我不明白如何访问个人
Mathematician
元素,然后运行 greet
在他们身上依次。我试过这样打印:
print (fmap greet ms)
并得到<interactive>:3:34: error:
• Couldn't match expected type ‘f0 Mathematician’ with actual type ‘Mathematicians’
• In the second argument of ‘fmap’, namely ‘ms’
In the first argument of ‘print’, namely ‘(fmap greet ms)’
In the expression: print (fmap greet ms)
使用 print (map greet ms)
反而:<interactive>:3:33: error:
• Couldn't match expected type ‘[Mathematician]’ with actual type ‘Mathematicians’
• In the second argument of ‘map’, namely ‘ms’
In the first argument of ‘print’, namely ‘(map greet ms)’
In the expression: print (map greet ms)
我很抱歉地说,这两者都不是,我完全理解。
最佳答案
mms
是 Maybe Mathematicians
,这意味着它可能不存在 Mathematicians
值(有点像其他语言中的 null
)。所以你需要“进入”Maybe
运行前 greet
在列表中的数学家。fmap :: (a -> b) -> Maybe a -> Maybe b
可以为你做这件事。我们要给fmap
一个函数,它变成 Mathematicians
成字符串列表(所以 a
是 Mathematicians
和 b
是 [String]
)。 fmap
将检查 Maybe
, 如果有值就运行函数,如果没有值就什么都不做。
greetMathematicians :: Maybe Mathematicians -> Maybe [String]
greetMathematicians mms = fmap (\ms -> [greet m | m <- mathematicians ms]) mms
关于parsing - 展开 Aeson 示例,如何使用值数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62938217/