我正在努力使用String
JSON作为输入并返回RoseTree
结构作为输出的函数。
我的代码如下:
import qualified Data.Aeson as JSON
import qualified Data.Text as T
import qualified Data.Aeson.Types as AT
import Control.Applicative
import qualified Data.ByteString.Char8 as BS
import Data.Attoparsec.ByteString.Char8
data RoseTree a = Empty | RoseTree a [RoseTree a]
deriving (Show)
instance (Show a) => JSON.ToJSON (RoseTree a) where
toJSON (RoseTree n cs) =
JSON.object [T.pack "value" JSON..= show n
, T.pack "children" JSON..= JSON.toJSON cs]
instance (Show a, JSON.FromJSON a) => JSON.FromJSON (RoseTree a) where
parseJSON (JSON.Object o) =
RoseTree <$> o JSON..: T.pack "value"
<*> o JSON..: T.pack "children"
parseRoseTreeFromJSON :: (Show a, JSON.FromJSON a) => String -> (RoseTree a)
parseRoseTreeFromJSON json =
let bs = BS.pack json in case parse JSON.json bs of
(Done rest r) -> case AT.parseMaybe JSON.parseJSON r of
(Just x) -> x
Nothing -> Empty
_ -> Empty
它将RoseTree
结构转换为JSON完全正常。例如,当我运行JSON.encode $ JSON.toJSON $ RoseTree 1 []
时,它会返回"{\"children\":[],\"value\":\"1\"}"
,正在运行JSON.encode $ JSON.toJSON $ RoseTree 1 [RoseTree 2 []]
会返回"{\"children\":[{\"children\":[],\"value\":\"2\"}],\"value\":\"1\"}"
。
但是当我尝试提供JSON时,我已经进入解析器的上一步,它总是返回Empty
:
*Main> parseRoseTreeFromJSON "{\"children\":[],\"value\":1}"
Empty
*Main> parseRoseTreeFromJSON "{\"children\":[{\"children\":[],\"value\":\"2\"}],\"value\":\"1\"}"
Empty
同样,
*Main> JSON.decode $ BLS.pack "{\"children\":[{\"children\":[],\"value\":\"2\"}],\"value\":\"1\"}"
Nothing
我怀疑我的解析器定义不正确。但我不知道到底出了什么问题。我正在使用正确的方法来处理递归解析吗?以递归方式执行此操作的正确方法是什么?
答案 0 :(得分:2)
奇怪的GHCi打字规则再次出现!如果添加类型注释,一切都按预期工作:
function palindrome(str) {
var str_array = str.toLowerCase().split("");
var no_space = str_array.filter(function(val) {
return val !== " ";
});
// By applying '.slice()', we create a new array
// reference which can then be reversed and assigned
// to the 'reverse' variable
var reverse = no_space.slice().reverse();
function check(a, b) {
var partial;
var result = 1;
for(var i=0; i < a.length; i++) {
if(a[i] !== b[i]) {
// We don't need to keep
// comparing the two, it
// already failed
return 0;
} else {
// I've kept this part even though
// I don't really know what it is
// intended for
partial = 1;
result *= partial;
}
}
return result;
}
return check(no_space, reverse) === 1;
}
console.log(palindrome("a b a"));
console.log(palindrome("r y e"));
在不知道您要解析的类型(它看到ghci> :set -XOverloadedStrings
ghci> JSON.decode "{\"children\":[],\"value\":1}" :: Maybe (RoseTree Int)
Just (RoseTree 1 [])
)的情况下,GHCi默认为FromJSON a => Maybe a
。你可以通过测试a ~ ()
实例并注意到它成功来试试这个!
FromJSON ()
如果这实际上是针对某个项目(并且不仅仅是为了娱乐和学习),还要对您的代码做一些注意事项:
ghci> JSON.decode "[]"
Just ()
(您基本上可以从代码中删除OverloadedStrings
的几乎所有用法,因为字符串文字将推断它们是否应该具有类型T.pack
,lazy / strict String
,lazy / strict Text
等。)ByteString
和DeriveGeneric
几乎免费获得JSON解析(尽管我承认行为略微与你现有的不同)根据这些建议,这里是对代码的重写:
DeriveAnyClass
请注意{-# LANGUAGE OverloadedStrings, DeriveGeneric, DeriveAnyClass #-}
import qualified Data.Aeson as JSON
import qualified Data.ByteString.Lazy.Char8 as BS
import GHC.Generics (Generic)
import Data.Maybe (fromMaybe)
data RoseTree a = RoseTree { value :: a, children :: [RoseTree a] }
deriving (Show, Generic, JSON.FromJSON, JSON.ToJSON)
中的decode
(几乎)Data.Aeson
做了什么......
parseRoseTreeFromJSON