let rec to_json: type a. a t -> json =   fun w ->     let call name (args : json list): json = `List (`String name :: args) in     match w with     | Fastq_gz file -> call "Fastq_gz" [`String file#product#path]     | Fastq file -> call "Fastq" [`String file#product#path]     | Bam_sample (name, file) ->       call "Bam-sample" [`String name; `String file#product#path]     | Bam_to_fastq (how, bam) ->       let how_string =         match how with `Paired -> "Paired" | `Single -> "Single" in       call "Bam-to-fastq" [`String how_string; to_json bam]     | Paired_end_sample ({sample_name; fragment_id}, r1, r2) ->       call "Paired-end" [`String sample_name; `String fragment_id;                          to_json r1; to_json r2]     | Single_end_sample ({sample_name; fragment_id}, r) ->       call "Single-end" [`String sample_name; `String fragment_id; to_json r]     | Gunzip_concat fastq_gz_list ->       call "Gunzip-concat" (List.map ~f:to_json fastq_gz_list)     | Concat_text fastq_list ->       call "Concat" (List.map ~f:to_json fastq_list)     | Bwa (config, input) ->       call "BWA" [         `Assoc ["configuration"Bwa.Configuration.Aln.to_json config];         to_json input       ]     | Bwa_mem (params, input) ->       let input_json = to_json input in       call "BWA-MEM" [         `Assoc ["configuration"Bwa.Configuration.Mem.to_json params];         input_json       ]     | Star (conf, input) ->       let input_json = to_json input in       call "STAR" [         `Assoc ["configuration"Star.Configuration.Align.to_json conf];         input_json;       ]     | Hisat (conf, input) ->       let input_json = to_json input in       call "HISAT" [         `Assoc ["configuration"Hisat.Configuration.to_json conf];         input_json;       ]     | Stringtie (conf, input) ->       let input_json = to_json input in       call "Stringtie" [         `Assoc ["configuration"Stringtie.Configuration.to_json conf];         input_json;       ]     | Mosaik (input) ->       let input_json = to_json input in       call "MOSAIK" [input_json]     | Gatk_indel_realigner ((indel_cfg, target_cfg), bam) ->       let open Gatk.Configuration in       let input_json = to_json bam in       let indel_cfg_json = Indel_realigner.to_json indel_cfg in       let target_cfg_json = Realigner_target_creator.to_json target_cfg in       call "Gatk_indel_realigner" [`Assoc [           "Configuration"`Assoc [             "IndelRealigner Configuration", indel_cfg_json;             "RealignerTargetCreator Configuration", target_cfg_json;           ];           "Input", input_json;         ]]     | Gatk_bqsr ((bqsr_cfg, print_reads_cfg), bam) ->       let open Gatk.Configuration in       let input_json = to_json bam in       call "Gatk_bqsr" [`Assoc [           "Configuration"`Assoc [             "Bqsr"Bqsr.to_json bqsr_cfg;             "Print_reads"Print_reads.to_json print_reads_cfg;           ];           "Input", input_json;         ]]     | Germline_variant_caller (gvc, bam) ->       call gvc.Variant_caller.name [`Assoc [           "Configuration", gvc.Variant_caller.configuration_json;           "Input", to_json bam;         ]]     | Picard_mark_duplicates (settings, bam) ->       (* The settings should not impact the output, so we don't dump them. *)       call "Picard_mark_duplicates" [`Assoc ["input", to_json bam]]     | Bam_pair (normal, tumor) ->       call "Bam-pair" [`Assoc ["normal", to_json normal; "tumor", to_json tumor]]     | Somatic_variant_caller (svc, bam_pair) ->       call svc.Variant_caller.name [`Assoc [           "Configuration", svc.Variant_caller.configuration_json;           "Input", to_json bam_pair;         ]]     | Seq2HLA input ->       call "Seq2HLA" [`Assoc [           "Input", to_json input         ]]     | Optitype (kind, input) ->       call "Optitype" [`Assoc [           "Input", to_json input;           "Kind"`String (match kind with `DNA -> "DNA" | `RNA -> "RNA")         ]]     | With_metadata (_, p) -> to_json p