struct

  type t = {
    forbid_empty_lines: bool;
    only_header_comment: bool;
    sharp_comments: bool;
    semicolon_comments: bool;
    max_items_per_line: int option;
    sequence: [ `int_sequence | `char_sequence of char list option ]
  }
  with sexp

  let char_sequence_default =
    { forbid_empty_lines = false;
      only_header_comment = false;
      sharp_comments = true;
      semicolon_comments = true;
      max_items_per_line = None;
      sequence = `char_sequence None }

  let int_sequence_default = { char_sequence_default with sequence = `int_sequence }

  let is_char_sequence t = t.sequence <> `int_sequence
  let is_int_sequence t = t.sequence = `int_sequence

  let forbid_empty_lines  tags = tags.forbid_empty_lines
  let only_header_comment tags = tags.only_header_comment
  let sharp_comments      tags = tags.sharp_comments
  let semicolon_comments  tags = tags.semicolon_comments
  let impose_sequence_alphabet tags =
    match tags.sequence with
    | `int_sequence -> None
    | `char_sequence (Some alphb) -> Some (fun c -> List.mem alphb c)
    | `char_sequence None -> None

  let max_items_per_line (t: t) =
    let default =
      match t.sequence with
      | `int_sequence -> 25
      | `char_sequence _ -> 72 in
    Option.value ~default t.max_items_per_line

  let comment_char (t: t) =
    if t.sharp_comments
    then Some '#'
    else if t.semicolon_comments
    then Some ';'
    else None

  let to_string t = sexp_of_t t |> Sexplib.Sexp.to_string
  let of_string s =
    try Ok (Sexplib.Sexp.of_string s |> t_of_sexp)
    with e -> Error (`tags_of_string e)


end