struct
  module Requirement = struct
    type t = [
      | `Processors of int 
          (** A number of cores on a shared-memory setting. *)

      | `Internet_access 
        (** Able to access public HTTP(S) or FTP URLs. *)

      | `Memory of [
          | `GB of float 
              (** Ask for a specific amount of memory. *)

          | `Small 
            (** Tell that the program does not expect HPC-like memory usage (i.e. not more than 2 GB or your usual laptop). *)

          | `Big 
            (** Tell that the program may ask for a lot of memory but you don't know how much precisely. *)

        ]
      | `Quick_run 
        (** Programs that run fast, with little resources. Usually, you can interpret this as "OK to run on the login node of my cluster." *)

      | `Spark of string list 
           (** Ask for a Spark (on-YARN) environment with custom parameters (not in use for now, "#WIP"). *)

      | `Custom of string 
          (** Pass arbitrary data (useful for temporary extensions/experiements outside of Biokepi). *)

      | `Self_identification of string list
        
        (** Set of names or tags for a workflow-node program to identify itself to the Machine.t. This is useful for quickly bypassing incorrect requirements set in the library (please also report an issue if you need this). *)

    ] [@@deriving yojson, show]
  end

  type t =
    ?name: string ->
    ?requirements: Requirement.t list ->
    Program.t ->
    KEDSL.Build_process.t
  
  (** The type of the “run function” used across the library. *)


  
  (** A stream processor, for this purpose, is a program that runs on one core and does not grow in memory arbitrarily. *)

  let stream_processor requirements =
    `Processors 1 :: `Memory `Small :: requirements

  let quick requirements = `Quick_run :: requirements

  let downloading requirements =
    `Internet_access :: stream_processor requirements 

  let with_self_ids ?self_ids l =
    match self_ids with
    | Some tags -> `Self_identification tags :: l
    | None -> l

  let with_requirements : t -> Requirement.t list -> t = fun f l ->
    fun ?name ?(requirements = []) prog ->
      f ?name ~requirements:(l @ requirements) prog
end