What is the best way to manage Haskell large records?

Replacing the field names with letters, I have such cases:

data Foo = Foo { a :: Maybe ...
               , b :: [...]
               , c :: Maybe ...
               , ... for a lot more fields ...
               } deriving (Show, Eq, Ord)

instance Writer Foo where
  write x = maybeWrite a ++
            listWrite  b ++
            maybeWrite c ++
            ... for a lot more fields ...

parser = permute (Foo
                   <$?> (Nothing, Just `liftM` aParser)
                   <|?> ([], bParser)
                   <|?> (Nothing, Just `liftM` cParser)
                   ... for a lot more fields ...

-- this is particularly hideous
foldl1 merge [foo1, foo2, ...]
merge (Foo a b c ...seriously a lot more...)
      (Foo a' b' c' ...) = 
        Foo (max a a') (b ++ b') (max c c') ...

What methods will allow me to better manage this growth?

In a perfect world a, band call are of the same type, so that I can keep them on the list, but they can be of different types. I am particularly interested in any way to collapse records without the need for massive templates.

I use this large record to store different types as a result of a permutation processing the vCard format .

Update

I implemented both generics and foldl approaches suggested below. They both work, and both of them reduce three large lists of fields to one.

+3
2

"" .

, , ( Show). , , "" , , .

generics-sop . Generics GGC , , sequence ap, .

generics-sop, merge funtion. :

{-# language TypeOperators #-}
{-# language DeriveGeneric #-}
{-# language TypeFamilies #-}
{-# language DataKinds #-}

import Control.Applicative (liftA2)
import qualified GHC.Generics as GHC
import Generics.SOP

A , , generics-sop:

fn_2' :: (a -> a -> a) -> (I -.-> (I -.-> I)) a -- I is simply an Identity functor
fn_2' = fn_2 . liftA2

, , Generic:

merge :: (Generic a, Code a ~ '[ xs ]) => NP (I -.-> (I -.-> I)) xs -> a -> a -> a 
merge funcs reg1 reg2 =
    case (from reg1, from reg2) of 
        (SOP (Z np1), SOP (Z np2)) -> 
            let npResult  = funcs `hap` np1 `hap` np2
            in  to (SOP (Z npResult))

Code - , , . , .

Code a ~ '[ xs ] , " ", , .

(SOP (Z _) () . SOP " ".

:

data Person = Person
    {
        name :: String
    ,   age :: Int
    } deriving (Show,GHC.Generic)

instance Generic Person -- this Generic is from generics-sop

mergePerson :: Person -> Person -> Person
mergePerson = merge (fn_2' (++) :* fn_2' (+) :* Nil)

Nil :* ( NP, n). , .

. , , , hcpure:

class Mergeable a where
    mergeFunc :: a -> a -> a

instance Mergeable String where
    mergeFunc = (++)

instance Mergeable Int where
    mergeFunc = (+)

mergePerson :: Person -> Person -> Person
mergePerson = merge (hcpure (Proxy :: Proxy Mergeable) (fn_2' mergeFunc))

hcliftA2 ( hcpure, fn_2 hap) .

+4

:

(1) RecordWildCards . , , . : ()

(2) , . Gabriel Gonzalez foldl. : ()

, , :

data Foo = Foo { _a :: Int, _b :: String }

_a _b_.

 import qualified Control.Foldl as L
 import Data.Profunctor

 data Foo = Foo { _a :: Int, _b :: String }
  deriving (Show)

 fold_a :: L.Fold Foo Int
 fold_a = lmap _a (L.Fold max 0 id)

 fold_b :: L.Fold Foo String
 fold_b = lmap _b (L.Fold (++) "" id)

 fold_foos :: L.Fold Foo Foo
 fold_foos = Foo <$> fold_a <*> fold_b

 theFoos = [ Foo 1 "a", Foo 3 "b", Foo 2 "c" ]

 test = L.fold fold_foos theFoos

Profunctor lmap , . :

L.Fold max 0 id

- Ints ( Num), :

lmap _a (L.Fold max 0 id)

- , Foo, _a .

+2

Source: https://habr.com/ru/post/1671381/


All Articles