List of data families - Haskell

Welcome to the Functional Programming Zulip Chat Archive. You can join the chat here.

Adam Flott

I'm looking to model logging outputs for a user library. The easiest approach would be a sum type with all the data I need:

data LogOutput
    = File Text
    | Console

However I want the user 1) to be able to make their own output 2) work with any number of outputs at run time. This was beginning to look like a good fit for data/type families, but I'm having trouble with desire 2. Is a list of data families possible or would another approach be more suitable?

A small example

data family LogOutput a

data Console = Console Bool
             deriving stock Show

data instance LogOutput Console = LogOutputConsole
                                deriving stock Show

data File = File Text

data instance LogOutput File = LogOutputFile Int

type LogOutputs a = [LogOutput a]

main = do
  let l = LogOutputConsole
      l2 = LogOutputFile 1

  print l
  let ls = [l, l2 ]
  print ls

Produces an expected error

play.hs:75:16: error:
    • Couldn't match type ‘File’ with ‘Console’
      Expected type: LogOutput Console
        Actual type: LogOutput File
    • In the expression: l2
      In the expression: [l, l2]
      In an equation for ‘ls’: ls = [l, l2]
   |
75 |   let ls = [l, l2 ]
   |                ^^
Torsten Schmits

not quite sure what you're intending to do with that Int but I suspect that the best way to start would be

data LogOutput a = File Text | Console | Custom a
Georgi Lyubenov // googleson78
I want the user 1) to be able to make their own output 2) work with any number of outputs at run time

sounds like you need an open union to me :thinking:

Georgi Lyubenov // googleson78

tho I haven't actually used any of them

Georgi Lyubenov // googleson78

actually I guess with the | Custom a approach the user can then use an open union themselves for the a

Georgi Lyubenov // googleson78

but I, for some reason, assumed Adam wants this built into the library

Torsten Schmits

still, what's the motivation for the open union?

Georgi Lyubenov // googleson78

so that the user can insert as many different "logging types" as they want

Georgi Lyubenov // googleson78

without having to add an open union impl. themselves

Georgi Lyubenov // googleson78

it could be wrapped in a nice interface that doesn't mention the underlying open union implementation at all

Torsten Schmits

what would the semantics of that be? you would have specialized logging types for individual subprograms?

Georgi Lyubenov // googleson78

ok, I agree, there's no point usually, the user can just define their own sum type of things they want to log

Georgi Lyubenov // googleson78

because usually you know what you're logging statically*

Torsten Schmits

it doesn't sound unreasonable to me if you have many logging types

Torsten Schmits

but it seems unlikely that you would have many logging types!

Georgi Lyubenov // googleson78

I guess if you want to restrict where you can log what using type signatures it might also be useful

Adam Flott

Duh! The Custom a actually does make things simple. However I still need something like hlist to handle a list of outputs for the case when a user has 2 different Custom outputs

Torsten Schmits

I would assume that your user would supply a handler function for their Custom a to your api function. if a is a sum type, they can just match on that