Haskell艾生处理缺失数据
Haskell Aeson to deal with missing data
我有一个(有效的)json 编码数组,其中包含缺失或格式错误的数据。我希望 Aeson 将其转换为 Maybe [Maybe Point]
并使 Nothing
数组元素无效 Point
.
import Data.Aeson
decode "[1,2,3,4,null,\"hello\"]" :: (Maybe [Maybe Int])
=> Nothing
但我更愿意将其计算为
=> Just [Just 1, Just 2, Just 3, Just 4, Nothing, Nothing]
如果 Aeson 无法做到这一点,是否有其他图书馆可以做到?
请注意,实际对象比简单整数复杂得多,因此字符串操作不是可行的解决方案。
首先,您的预期结果不是 (Maybe [Maybe Int])
类型,而是 [Maybe Int]
.
类型
其次,根据decode
的定义,这是不可能的。然而,您可以使用 decode
将 JSON 数组解码为 Aeson 值列表,然后您可以映射并解码实际值。
因此,单个值的解析器错误不会导致整个数组的解析器错误。
编辑:当您修改您的期望时,这可能会对您有所帮助:
Prelude Data.ByteString.Lazy.Char8 Data.Aeson> (decode (pack "[1,2,3,null,\"hello\"]") :: Maybe [Value])
Just [Number 1.0,Number 2.0,Number 3.0,Null,String "hello"]
从那里,您可以映射和匹配以满足您的需要(因为仅舍入浮点数可能不合适)。
我会使用值并从中工作:
decode "[1,2,3,4,null,\"hello\"]" :: (Maybe [Value])
Just [Number 1.0,Number 2.0,Number 3.0,Number 4.0,Null,String "hello"]
所以
> let fromNum v = case v of Number x -> Just x ; _ -> Nothing
> maybe [] (map fromNum) (decode "[1,2,3,4,null,\"hello\"]" :: (Maybe [Value])
[Just 1.0,Just 2.0,Just 3.0,Just 4.0,Nothing,Nothing]
一个非常无效(但安全)的解决方案是:
> let tmp = maybe [] (map fromNum) (decode "[1,2,3,4,null,\"hello\"]" :: (Maybe [Value])
> let keepJust l v = case v of Just i -> i:l; Nothing -> l
> reverse (foldl keepJust [] tmp)
[1.0,2.0,3.0,4.0]
如果你想让事情更有效,你可能想使用 Vector
s 和 foldl'
。
我们可以围绕 Maybe
创建一个新类型,它在解析失败时不会失败,而是在 Nothing
:
时成功
{-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving #-}
import Data.Aeson
import Data.Coerce
import Control.Applicative
import Control.Monad
newtype Maybe' a = Maybe' (Maybe a) deriving
(Eq, Ord, Show, Functor, Applicative, Monad, Alternative, MonadPlus)
instance FromJSON a => FromJSON (Maybe' a) where
parseJSON v = do
case fromJSON v :: Result a of
Success a -> pure (Maybe' $ Just a)
_ -> pure (Maybe' $ Nothing)
现在我们可以用 Maybe'
包装类型以获得所需的行为:
> decode "[4, 5, \"foo\", \"bar\"]" :: Maybe [Maybe' Int]
Just [Maybe' (Just 4),Maybe' (Just 5),Maybe' Nothing,Maybe' Nothing]
但是,我们很有可能希望在之后使用常规 Maybe
值。 Data.Coerce
在这里派上用场,因为它允许我们将所有 Maybe'
-s 强制转换为 Maybe
-s,无论它们在结果类型中的什么位置:
> coerce (decode "[[[], 3], [4, 5]]" :: Maybe [(Maybe' Int, Int)]) :: Maybe [(Maybe Int, Int)]
Just [(Nothing,3),(Just 4,5)]
我有一个(有效的)json 编码数组,其中包含缺失或格式错误的数据。我希望 Aeson 将其转换为 Maybe [Maybe Point]
并使 Nothing
数组元素无效 Point
.
import Data.Aeson
decode "[1,2,3,4,null,\"hello\"]" :: (Maybe [Maybe Int])
=> Nothing
但我更愿意将其计算为
=> Just [Just 1, Just 2, Just 3, Just 4, Nothing, Nothing]
如果 Aeson 无法做到这一点,是否有其他图书馆可以做到?
请注意,实际对象比简单整数复杂得多,因此字符串操作不是可行的解决方案。
首先,您的预期结果不是 (Maybe [Maybe Int])
类型,而是 [Maybe Int]
.
其次,根据decode
的定义,这是不可能的。然而,您可以使用 decode
将 JSON 数组解码为 Aeson 值列表,然后您可以映射并解码实际值。
因此,单个值的解析器错误不会导致整个数组的解析器错误。
编辑:当您修改您的期望时,这可能会对您有所帮助:
Prelude Data.ByteString.Lazy.Char8 Data.Aeson> (decode (pack "[1,2,3,null,\"hello\"]") :: Maybe [Value])
Just [Number 1.0,Number 2.0,Number 3.0,Null,String "hello"]
从那里,您可以映射和匹配以满足您的需要(因为仅舍入浮点数可能不合适)。
我会使用值并从中工作:
decode "[1,2,3,4,null,\"hello\"]" :: (Maybe [Value])
Just [Number 1.0,Number 2.0,Number 3.0,Number 4.0,Null,String "hello"]
所以
> let fromNum v = case v of Number x -> Just x ; _ -> Nothing
> maybe [] (map fromNum) (decode "[1,2,3,4,null,\"hello\"]" :: (Maybe [Value])
[Just 1.0,Just 2.0,Just 3.0,Just 4.0,Nothing,Nothing]
一个非常无效(但安全)的解决方案是:
> let tmp = maybe [] (map fromNum) (decode "[1,2,3,4,null,\"hello\"]" :: (Maybe [Value])
> let keepJust l v = case v of Just i -> i:l; Nothing -> l
> reverse (foldl keepJust [] tmp)
[1.0,2.0,3.0,4.0]
如果你想让事情更有效,你可能想使用 Vector
s 和 foldl'
。
我们可以围绕 Maybe
创建一个新类型,它在解析失败时不会失败,而是在 Nothing
:
{-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving #-}
import Data.Aeson
import Data.Coerce
import Control.Applicative
import Control.Monad
newtype Maybe' a = Maybe' (Maybe a) deriving
(Eq, Ord, Show, Functor, Applicative, Monad, Alternative, MonadPlus)
instance FromJSON a => FromJSON (Maybe' a) where
parseJSON v = do
case fromJSON v :: Result a of
Success a -> pure (Maybe' $ Just a)
_ -> pure (Maybe' $ Nothing)
现在我们可以用 Maybe'
包装类型以获得所需的行为:
> decode "[4, 5, \"foo\", \"bar\"]" :: Maybe [Maybe' Int]
Just [Maybe' (Just 4),Maybe' (Just 5),Maybe' Nothing,Maybe' Nothing]
但是,我们很有可能希望在之后使用常规 Maybe
值。 Data.Coerce
在这里派上用场,因为它允许我们将所有 Maybe'
-s 强制转换为 Maybe
-s,无论它们在结果类型中的什么位置:
> coerce (decode "[[[], 3], [4, 5]]" :: Maybe [(Maybe' Int, Int)]) :: Maybe [(Maybe Int, Int)]
Just [(Nothing,3),(Just 4,5)]