hasexp / comb.ml

open Spotlib.Spot

type 'a _filter = 'a -> 'a Stream.t
(** Type of filter, which takes a tree,
    and returns the stream of subtrees which match with the filter criteria
*)

module type TreeType = sig

  type t (** type of the tree *)

  val leaf : t _filter
  (** Return the singleton of the tree if it is a terminal node.
      Otherwise returns null. *)

  val branch : t _filter
  (** Return the singleton of tree if it is a branch node. 
      Otherwise returns null. *)

  val children : t _filter
  (** return the sub-nodes *)
end 

module type S = sig
  include TreeType
  type filter = t _filter 
  val none : filter
  val keep : filter
  val ( *<| ) : filter -> filter -> filter
  val ( *>| ) : filter -> filter -> filter
  val ( ||| ) : filter -> filter -> filter
  val with_   : filter -> filter -> filter
  val without : filter -> filter -> filter
  val ( /> )  : filter -> filter -> filter
  val ( </ )  : filter -> filter -> filter
  val if_ : filter -> then_:filter -> else_:filter -> filter
  val ( |>| ) : filter -> filter -> filter
  val deep : filter -> filter
  val deepest : filter -> filter
end

module Make(Tree : TreeType) : S with type t := Tree.t = struct
  open Stream

  include Tree

  type filter = t _filter

  let none _ = null

  let keep t = singleton t

  let ( *<| ) f g = fun t -> g t >>= f
  let ( *>| ) f g = fun t -> f t >>= g

  let (|||) f g = fun t -> append (f t) (g t)
  let with_ f g = f *> filter (fun v -> not (is_null (g v)))
  let without f g = f *> filter (g *> is_null)

  let (/>) f g = f *>| children *>| g
  let (</) f g = with_ f (children *>| g)

  let if_ f ~then_ ~else_ = fun t -> lazy begin
    if not (is_null (f t)) 
    then Lazy.force (then_ t) 
    else Lazy.force (else_ t)
  end

  let (|>|) f g = fun t -> lazy begin
    let t' = f t in
    if not (is_null t') then Lazy.force t' else Lazy.force (g t)
  end

  let rec deep f = 
    (* eta-expansion requred to prevent inf loop *)
    f |>| fun t -> (children *>| deep f) t

  let rec deepest f = (fun t -> (children *>| deepest f) t) |>| f

end
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.