我正在尝试通过https://www.fpcomplete.com/school/pick-of-the-week/episode-1-json在 Haskell 中学习解析 JSON
当我加载文件(显示在此交互式列表之后)时,我得到:
> ghci
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :set -v
hiding package binary-0.5.1.1 to avoid conflict with later version binary-0.7.1.0
hiding package Cabal-1.16.0 to avoid conflict with later version Cabal-1.18.0
hiding package QuickCheck-2.4.2 to avoid conflict with later version QuickCheck-2.6
hiding package syb-0.3.7 to avoid conflict with later version syb-0.4.0
hiding package hakyll-4.2.2.0 to avoid conflict with later version hakyll-4.3.1.0
wired-in package ghc-prim mapped to ghc-prim-0.3.0.0-d5221a8c8a269b66ab9a07bdc23317dd
wired-in package integer-gmp mapped to integer-gmp-0.5.0.0-2f15426f5b53fe4c6490832f9b20d8d7
wired-in package base mapped to base-4.6.0.1-6c351d70a24d3e96f315cba68f3acf57
wired-in package rts mapped to builtin_rts
wired-in package template-haskell mapped to template-haskell-2.8.0.0-c2c1b21dbbb37ace4b7dc26c966ec664
wired-in package dph-seq not found.
wired-in package dph-par not found.
Prelude> :l X03ObjSetsTweetReader
*** Chasing dependencies:
Chasing modules from:
Stable obj: []
Stable BCO: []
unload: retaining objs []
unload: retaining bcos []
Ready for upsweep []
Upsweep completely successful.
*** Deleting temp files:
Deleting:
*** Chasing dependencies:
Chasing modules from: *X03ObjSetsTweetReader.hs
Stable obj: []
Stable BCO: []
unload: retaining objs []
unload: retaining bcos []
Ready for upsweep
[NONREC
ModSummary {
ms_hs_date = 2013-10-02 02:30:39 UTC
ms_mod = main:X03ObjSetsTweetSetTest,
ms_textual_imps = [import (implicit) Prelude, import Control.Monad,
import Control.Applicative, import Data.Monoid, import Data.Aeson,
import Parser (),
import qualified Data.ByteString.Lazy.Char8 as C8,
import qualified Data.ByteString.Lazy as BL]
ms_srcimps = []
}]
*** Deleting temp files:
Deleting:
compile: input file X03ObjSetsTweetReader.hs
Created temporary directory: /var/folders/dw/c7gq7tw9339grqjctgwbmgzm0000gy/T/ghc18739_0
*** Checking old interface for main:X03ObjSetsTweetSetTest:
[1 of 1] Compiling X03ObjSetsTweetSetTest ( X03ObjSetsTweetReader.hs, interpreted )
*** Parser:
*** Renamer/typechecker:
*** Desugar:
Result size of Desugar (after optimization)
= {terms: 974, types: 767, coercions: 0}
*** Simplifier:
Result size of Simplifier iteration=1
= {terms: 966, types: 761, coercions: 45}
Result size of Simplifier = {terms: 966, types: 761, coercions: 45}
*** Tidy Core:
Result size of Tidy Core = {terms: 966, types: 761, coercions: 45}
*** CorePrep:
Result size of CorePrep
= {terms: 1,646, types: 1,390, coercions: 45}
*** ByteCodeGen:
Upsweep completely successful.
*** Deleting temp files:
Deleting: /var/folders/dw/c7gq7tw9339grqjctgwbmgzm0000gy/T/ghc18739_0/ghc18739_0.c /var/folders/dw/c7gq7tw9339grqjctgwbmgzm0000gy/T/ghc18739_0/ghc18739_0.o
Warning: deleting non-existent /var/folders/dw/c7gq7tw9339grqjctgwbmgzm0000gy/T/ghc18739_0/ghc18739_0.c
Warning: deleting non-existent /var/folders/dw/c7gq7tw9339grqjctgwbmgzm0000gy/T/ghc18739_0/ghc18739_0.o
Ok, modules loaded: X03ObjSetsTweetSetTest.
*X03ObjSetsTweetSetTest> main
*** Parser:
*** Desugar:
*** Simplify:
*** CorePrep:
*** ByteCodeGen:
Loading package array-0.4.0.1 ... linking ... done.
Loading package deepseq-1.3.0.1 ... linking ... done.
Loading package primitive-0.5.0.1 ... linking ... done.
Loading package vector-0.10.0.1 ... linking ... done.
Loading package bytestring-0.10.0.2 ... linking ... done.
Loading package text-0.11.3.1 ... linking ... done.
Loading package hashable-1.1.2.5 ... linking ... done.
Loading package unordered-containers-0.2.3.0 ... linking ... done.
Loading package transformers-0.3.0.0 ... linking ... done.
Loading package mtl-2.1.2 ... linking ... done.
Loading package parsec-3.1.3 ... linking ... done.
Loading package containers-0.5.0.0 ... linking ... done.
Loading package attoparsec-0.10.4.0 ... linking ... done.
Loading package pretty-1.1.1.0 ... linking ... done.
Loading package old-locale-1.0.0.5 ... linking ... done.
Loading package time-1.4.0.1 ... linking ... done.
Loading package HUnit-1.2.5.2 ... linking ... done.
Loading package random-1.0.1.1 ... linking ... done.
Loading package template-haskell ... linking ... done.
Loading package QuickCheck-2.6 ... linking ... done.
Loading package type-equality-0.1.2 ... linking ... done.
Loading package RepLib-0.5.3.1 ... linking ... done.
Loading package bimap-0.2.4 ... linking ... done.
Loading package filepath-1.3.0.1 ... linking ... done.
*** gcc:
'/usr/bin/gcc' '-m64' '-fno-stack-protector' '-m64' '-L/Library/Frameworks/GHC.framework/Versions/7.6.3-x86_64/usr/lib/ghc-7.6.3/unix-2.6.0.1' '--print-file-name' 'libdl.dylib'
Loading package unix-2.6.0.1 ... linking ... done.
Loading package directory-1.2.0.1 ... linking ... done.
Loading package unbound-0.4.2 ... linking ... done.
Loading package pi-forall-0.1 ... linking ... <interactive>:
lookupSymbol failed in relocateSection (relocate external)
/Users/carr/Library/Haskell/ghc-7.6.3/lib/pi-forall-0.1/lib/HSpi-forall-0.1.o: unknown symbol `_pizmforallzm0zi1_LayoutToken_makeTokenParser_info'
ghc: unable to load package `pi-forall-0.1'
*X03ObjSetsTweetSetTest>
为什么它会加载pi-forall
?那是来自 OPLSS 2013 的 Stephanie Weirich 的演示 impl。我如何追踪加载此内容的人员/内容/原因?
这是 X03ObjSetsTweetSetTest.hs:
module X03ObjSetsTweetSetTest where
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as C8
import Parser()
import Data.Aeson
import Data.Monoid
import Control.Applicative
import Control.Monad
data Recipe = Recipe
{ recipeName :: String
, ingredients :: [Ingredient]
, steps :: [Step]
} deriving Show
type Measure = String
data Ingredient = Ingredient
{ ingredientName :: String
, quantity :: Int
, measure :: Maybe Measure
} deriving Show
data Step = Step
{ stepName :: String
, order :: Int
, stepDuration :: Maybe Duration
} deriving (Eq, Show)
instance Ord Step where
compare s1 s2 = compare (order s1) (order s2)
data Duration = Duration
{ duration :: Int
, durationMeasure :: Measure
} deriving (Eq, Show)
-------------------------------------------------------------------------------
instance FromJSON Recipe where
parseJSON (Object r) = Recipe <$>
r .: "name" <*>
r .: "ingredients" <*>
r .: "steps"
parseJSON _ = mzero
instance ToJSON Recipe where
toJSON (Recipe n i s) = object ["name" .= n, "ingredients" .= i, "steps" .= s]
-------------------------------------------------------------------------------
instance FromJSON Step where
parseJSON (Object s) = Step <$>
s .: "step" <*>
s .: "order" <*>
s .:? "duration"
parseJSON _ = mzero
instance ToJSON Step where
toJSON (Step s o d) = object ["step" .= s, "order" .= o, "duration" .= d]
-------------------------------------------------------------------------------
instance FromJSON Ingredient where
parseJSON (Object i) = Ingredient <$>
i .: "name" <*>
i .: "quantity" <*>
i .:? "measure"
parseJSON _ = mzero
instance ToJSON Ingredient where
toJSON (Ingredient n q m) = object ["name" .= n, "quantity" .= q, "measure" .= m]
-------------------------------------------------------------------------------
instance FromJSON Duration where
parseJSON (Object d) = Duration <$>
d .: "duration" <*>
d .: "measure"
parseJSON _ = mzero
instance ToJSON Duration where
toJSON (Duration d m) = object ["duration" .= d, "measure" .= m]
-------------------------------------------------------------------------------
main :: IO ()
main = do
let toParse = C8.unlines $ map C8.pack [
"{ ",
" \"name\": \"Ciambellone Cake\", ",
" \"ingredients\": [ ",
" { ",
" \"name\": \"Flour\", ",
" \"quantity\": 250, ",
" \"measure\": \"gr\" ",
" }, ",
" { ",
" \"name\": \"Sugar\", ",
" \"quantity\": 250, ",
" \"measure\": \"gr\" ",
" }, ",
" { ",
" \"name\": \"Sunflower Oil\", ",
" \"quantity\": 130, ",
" \"measure\": \"ml\" ",
" }, ",
" { ",
" \"name\": \"Water\", ",
" \"quantity\": 130, ",
" \"measure\": \"ml\" ",
" }, ",
" { ",
" \"name\": \"Egg\", ",
" \"quantity\": 3 ",
" }, ",
" { ",
" \"name\": \"Yeast\", ",
" \"quantity\": 1 ",
" } ",
" ], ",
" \"steps\": [ ",
" { ",
" \"step\": \"Mix everything\", ",
" \"order\": 1 ",
" }, ",
" { ",
" \"step\": \"Cook in oven at 200 degrees\", ",
" \"order\": 2, ",
" \"duration\": { ",
" \"duration\": 30, ",
" \"measure\": \"minutes\" ",
" } ",
" } ",
" ] ",
"} "
]
in case (eitherDecode' toParse :: Either String Recipe) of
Right r -> print r
Left e -> C8.putStrLn $ C8.pack e <> " in " <> toParse