Haskell record syntax and type classes

后端 未结 4 1149
抹茶落季
抹茶落季 2020-12-17 14:57

Suppose that I have two data types Foo and Bar. Foo has fields x and y. Bar has fields x and z. I want to be able to write a function that takes either a Foo or a Bar as

相关标签:
4条回答
  • 2020-12-17 15:32

    Seems to me like a job for generics. If you could tag your Int with different newtypes, then you would be able to write (with uniplate, module PlateData):

    data Foo = Foo Something Another deriving (Data,Typeable)
    data Bar = Bar Another Thing deriving (Data, Typerable)
    
    data Opts = F Foo | B Bar
    
    newtype Something = S Int
    newtype Another = A Int
    newtype Thing = T Int
    
    getAnothers opts = [ x | A x <- universeBi opts ]
    

    This would extract all Another's from anywhere inside the Opts.

    Modification is possible as well.

    0 讨论(0)
  • 2020-12-17 15:37

    You could use code such as

    data Foo = Foo { fooX :: Int, fooY :: Int } deriving (Show)
    data Bar = Bar { barX :: Int, barZ :: Int } deriving (Show)
    
    instance HasX Foo where
      getX = fooX
      setX r x' = r { fooX = x' }
    
    instance HasX Bar where
      getX = barX
      setX r x' = r { barX = x' }
    

    What are you modeling in your code? If we knew more about the problem, we could suggest something less awkward than this object-oriented design shoehorned into a functional language.

    0 讨论(0)
  • 2020-12-17 15:48

    You want extensible records which, I gather, is one of the most talked about topics in Haskell. It appears that there is not currently much consensus on how to implement it.

    In your case it seems like maybe instead of an ordinary record you could use a heterogeneous list like those implemented in HList.

    Then again, it seems you only have two levels here: common and program. So maybe you should just define a common record type for the common options and a program-specific record type for each program, and use StateT on a tuple of those types. For the common stuff you can add aliases that compose fst with the common accessors so it's invisible to callers.

    0 讨论(0)
  • 2020-12-17 15:53

    If you make the types instances of Foldable you get a toList function that you can use as the basis of your accessor.

    If Foldable doesn't by you anything, then maybe the right approach is to define the interface you want as a type class and figure out a good way to autogenerate the derived values.

    Perhaps by deriving from doing

    deriving(Data)
    

    you could use gmap combinators to base your access off.

    0 讨论(0)
提交回复
热议问题