扩展Aeson例子,如何使用数组值?
Expanding Aeson example, how to use array of values?
我想多了解一点 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)
和 get
<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
)。所以你需要在列表中的数学家运行宁greet
之前“进入”Maybe
。
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
您可以使用 mapM_ :: (Monad m, Foldable f) => (a -> m b) -> f a -> m ()
到 运行 对 Foldable
:
的所有元素的单子操作
greet :: Mathematician -> String
greet Mathematician { name=n, born=b } = n ++ " was born " ++ show b
main = do
input <- B.readFile "mathematicians.json"
case A.decode input :: Maybe Mathematicians of
Nothing -> print "error parsing JSON"
Just (Mathematicians ms) -> <b>mapM_ (putStrLn . greet) ms</b>
我想多了解一点 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)
和 get
<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
)。所以你需要在列表中的数学家运行宁greet
之前“进入”Maybe
。
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
您可以使用 mapM_ :: (Monad m, Foldable f) => (a -> m b) -> f a -> m ()
到 运行 对 Foldable
:
greet :: Mathematician -> String
greet Mathematician { name=n, born=b } = n ++ " was born " ++ show b
main = do
input <- B.readFile "mathematicians.json"
case A.decode input :: Maybe Mathematicians of
Nothing -> print "error parsing JSON"
Just (Mathematicians ms) -> <b>mapM_ (putStrLn . greet) ms</b>