Haskell:从Maybes结构转换为Hashmap

Haskell:从Maybes结构转换为Hashmap,haskell,haskell-lens,Haskell,Haskell Lens,我经常出现一种模式。我有一个这样的结构: data Foo = Foo { foo :: Maybe Text , bar :: Maybe Text , buz :: Maybe Text } 我想将其转换为带有标签值的贴图,不丢弃任何值: myMap :: [(Text, Text)] 例如:myMap=[(“foo”,“val1”),(“bar”,“val2”)] 最优雅的方式是什么? 我尝试了一些模式,比如if is just。。。然后我就。。。除此之外,什么都

我经常出现一种模式。我有一个这样的结构:

data Foo = Foo
  { foo  :: Maybe Text
  , bar  :: Maybe Text
  , buz  :: Maybe Text
  }
我想将其转换为带有标签值的贴图,不丢弃任何值:

myMap :: [(Text, Text)]
例如:
myMap=[(“foo”,“val1”),(“bar”,“val2”)]

最优雅的方式是什么? 我尝试了一些模式,比如
if is just。。。然后我就。。。除此之外,什么都不做,然后使用
catMaybes
,但在我看来它不是很优雅

实际上,我的结构更加异构:

data Foo = Foo
  { foo  :: Maybe Text
  , bar  :: Maybe Bool
  , buz  :: Maybe Int
  }
我想把它转换成:

myMap :: [(Text, Value)]

有没有一种镜头方式可以做到这一点?

不是镜头,但至少列表理解很简单:

quux :: Foo -> [(String, Text)]
quux v = [ (a,b) | (a, Just b) <- zip ["foo", "bar", "buz"] 
                                 $ map ($ v) [foo, bar, buz]]

是的,这很快就会变得脆弱和笨拙。但是第一个变体非常简单。

我们可以让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 ToJSON Foo
例如:

Prelude> kvs (Foo Nothing (Just True) (Just 14))
[("buz",Number 14.0),("bar",Bool True)]

类型签名,如
myMap::[(文本,值)]
似乎意味着所有字段都具有相同的类型。列表必须是同质的。@jpmarinier抱歉,我忘了提到它是来自Aeson的值:@cdupont:您可以让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 ToJSON Foo
import Data.Aeson(Value(Null, Object), toJSON)
import Data.HashMap.Strict(toList)

kvs :: Foo -> [(Text, Value)]
kvs foo
    | Object obs <- toJSON foo = filter ((Null /=) . snd) (toList obs)
    | otherwise = []
Prelude> kvs (Foo Nothing (Just True) (Just 14))
[("buz",Number 14.0),("bar",Bool True)]