Haskell: 从 Maybes 结构转换为 Hashmap
Haskell: convert from a structure of Maybes to a Hashmap
我经常出现一种模式。我有这样一个结构:
data Foo = Foo
{ foo :: Maybe Text
, bar :: Maybe Text
, buz :: Maybe Text
}
我想将其转换为带有标签值的地图,丢弃无值:
myMap :: [(Text, Text)]
例如:myMap = [("foo", "val1"), ("bar", "val2")]
最优雅的方法是什么?
我尝试过 if isJust ... then fromJust ... else Nothing
等模式,然后使用 catMaybes
但它不是很优雅的 IMO。
实际上我的结构更加异构:
data Foo = Foo
{ foo :: Maybe Text
, bar :: Maybe Bool
, buz :: Maybe Int
}
我想将其转换为:
myMap :: [(Text, Value)]
是否有 Lens 方法?
不是镜头,但至少它对列表理解很简单:
quux :: Foo -> [(String, Text)]
quux v = [ (a,b) | (a, Just b) <- zip ["foo", "bar", "buz"]
$ map ($ v) [foo, bar, buz]]
或者您的第二个请求,
quux2 :: Foo -> [(String, Value)]
quux2 v = [ (a,b) | (a, Just b) <- zip ["foo", "bar", "buz"]
$ map ($ v)
[(TextValue <$>) . foo,
(BoolValue <$>) . bar, (IntValue <$>) . buz]]
假设
TextValue :: Text -> Value
BoolValue :: Bool -> Value
IntValue :: Int -> Value
是的,这很快就会变得脆弱和笨重。但是第一个变体很简单。
我们可以让Haskell自动派生出ToJson
的实例:
{-# LANGUAGE DeriveGeneric #-}
import Data.Text(Text)
import Data.Aeson(ToJSON)
import GHC.Generics(Generic)
data Foo = Foo
{ foo :: Maybe Text
, bar :: Maybe Bool
, buz :: Maybe Int
} deriving Generic
instance <b>ToJSON Foo</b>
然后您可以筛选出值为 Null
:
的项目
import Data.Aeson(Value(Null, Object), toJSON)
import Data.HashMap.Strict(toList)
kvs :: Foo -> [(Text, Value)]
kvs foo
| Object <b>obs</b> <- toJSON foo = filter ((Null /=) . snd) (toList obs)
| otherwise = []
例如:
Prelude> kvs (Foo Nothing (Just True) (Just 14))
[("buz",Number 14.0),("bar",Bool True)]
我经常出现一种模式。我有这样一个结构:
data Foo = Foo
{ foo :: Maybe Text
, bar :: Maybe Text
, buz :: Maybe Text
}
我想将其转换为带有标签值的地图,丢弃无值:
myMap :: [(Text, Text)]
例如:myMap = [("foo", "val1"), ("bar", "val2")]
最优雅的方法是什么?
我尝试过 if isJust ... then fromJust ... else Nothing
等模式,然后使用 catMaybes
但它不是很优雅的 IMO。
实际上我的结构更加异构:
data Foo = Foo
{ foo :: Maybe Text
, bar :: Maybe Bool
, buz :: Maybe Int
}
我想将其转换为:
myMap :: [(Text, Value)]
是否有 Lens 方法?
不是镜头,但至少它对列表理解很简单:
quux :: Foo -> [(String, Text)]
quux v = [ (a,b) | (a, Just b) <- zip ["foo", "bar", "buz"]
$ map ($ v) [foo, bar, buz]]
或者您的第二个请求,
quux2 :: Foo -> [(String, Value)]
quux2 v = [ (a,b) | (a, Just b) <- zip ["foo", "bar", "buz"]
$ map ($ v)
[(TextValue <$>) . foo,
(BoolValue <$>) . bar, (IntValue <$>) . buz]]
假设
TextValue :: Text -> Value
BoolValue :: Bool -> Value
IntValue :: Int -> Value
是的,这很快就会变得脆弱和笨重。但是第一个变体很简单。
我们可以让Haskell自动派生出ToJson
的实例:
{-# LANGUAGE DeriveGeneric #-}
import Data.Text(Text)
import Data.Aeson(ToJSON)
import GHC.Generics(Generic)
data Foo = Foo
{ foo :: Maybe Text
, bar :: Maybe Bool
, buz :: Maybe Int
} deriving Generic
instance <b>ToJSON Foo</b>
然后您可以筛选出值为 Null
:
import Data.Aeson(Value(Null, Object), toJSON)
import Data.HashMap.Strict(toList)
kvs :: Foo -> [(Text, Value)]
kvs foo
| Object <b>obs</b> <- toJSON foo = filter ((Null /=) . snd) (toList obs)
| otherwise = []
例如:
Prelude> kvs (Foo Nothing (Just True) (Just 14))
[("buz",Number 14.0),("bar",Bool True)]