6

I have a data type like this:

data MyType = Foo Bool
            | Bar
            | Baz Bool (Maybe String) Bool
            | Quux Int String

Can I use generics to write a function getBools :: MyType -> [Bool] that returns a list of all the boolean fields in the input?

I came up with this type signature:

getAllOfType ::
  (Generic inner, Generic outer, HasDatatypeInfo inner, All2 HasDatatypeInfo (Code outer)) =>
  Proxy inner -> outer -> [inner]

Using generics-sop, but I don't think that's right. Comparing the DatatypeInfos is not going to convince the type checker that the two types are equivalent.

Echo Nolan
  • 1,111
  • 1
  • 11
  • 23
  • 3
    If you own `MyType` then you can write `MyType' a = Foo a | ...`, replacing `Bool` with `a` everywhere and `type MyType = MyType' Bool`. Then you can derive `Foldable` (with the `DeriveFoldable` extension) and `toList` will give you a list of all of the `Bool`s in your structure. No generics required. – Rein Henrichs Jul 21 '17 at 20:11
  • That's interesting, but doesn't really work for me. In reality, I want to extract different fields depending on use case. – Echo Nolan Jul 21 '17 at 20:14

1 Answers1

6

Using uniplate:

{-# LANGUAGE DeriveDataTypeable #-}

module M where

import Data.Data
import Data.Generics.Uniplate.Data

data MyType
  = Foo Bool
  | Bar
  | Baz Bool (Maybe String) Bool
  | Quux Int String
  deriving Data

getBools :: MyType -> [Bool]
getBools = universeBi
soupi
  • 1,013
  • 6
  • 6