1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
type parser_error = [ `Bed_parser_error of int * string ]
[@@deriving sexp]
module Field = Table.Field
type item = string * int * int * string list
let item_of_line l =
let open Result in
match Line.split l ~on:'\t' with
| chrom :: chrom_start :: chrom_end :: others ->
Field.(parse ~ctx:"chrom_start" int) chrom_start >>= fun chrom_start ->
Field.(parse ~ctx:"chrom_end" int) chrom_end >>| fun chrom_end ->
chrom, chrom_start, chrom_end, others
| _ -> Error "Expected at least 3 fields separated by tab characters"
let line_of_item (chr, start_pos, stop_pos, others) =
String.concat ~sep:"\t" (chr :: Int.to_string start_pos :: Int.to_string stop_pos :: others)
|> Line.of_string_unsafe
module Bed3 = struct
type item = {
chrom : string ;
chrom_start : int ;
chrom_end : int ;
others : string array ;
}
[@@deriving sexp]
end
module Bed4 = struct
type item = {
chrom : string ;
chrom_start : int ;
chrom_end : int ;
name : string ;
others : string array ;
}
[@@deriving sexp]
end
module Bed5_raw = struct
type item = {
chrom : string ;
chrom_start : int ;
chrom_end : int ;
name : string ;
score : int ;
others : string list ;
}
[@@deriving sexp]
let make ~chrom ~chrom_start ~chrom_end ~name ~score ?(others = []) () =
let open Result in
Field.(parse ~ctx:"chrom" string_with_no_sep) chrom >>= fun chrom ->
Field.(parse ~ctx:"name" string_with_no_sep) name >>= fun name ->
Field.(parse_all string_with_no_sep) others >>= fun others ->
Ok { chrom ; chrom_start ; chrom_end ; name ; score ; others }
let set_score it score = { it with score }
let item_of_line l =
let open Result in
match Line.split l ~on:'\t' with
| chrom :: chrom_start :: chrom_end :: name :: score :: others ->
Field.(parse ~ctx:"chrom_start" int) chrom_start >>= fun chrom_start ->
Field.(parse ~ctx:"chrom_end" int) chrom_end >>= fun chrom_end ->
Field.(parse ~ctx:"score" int) score >>= fun score ->
Ok { chrom ; chrom_start ; chrom_end ; name ; score ; others }
| _ -> Error "Expected at least 5 fields separated by tab characters"
let line_of_item it =
it.chrom ::
Int.to_string it.chrom_start ::
Int.to_string it.chrom_end ::
it.name ::
Int.to_string it.score ::
it.others
|> String.concat ~sep:"\t"
|> Line.of_string_unsafe
end
module Bed5 = struct
include Bed5_raw
let make ~chrom ~chrom_start ~chrom_end ~name ~score ?(others = []) () =
let open Result in
Field.(parse ~ctx:"chrom" string_with_no_sep) chrom >>= fun chrom ->
Field.(parse ~ctx:"name" string_with_no_sep) name >>= fun name ->
Field.(parse_all ~ctx:"others" string_with_no_sep) others >>= fun others ->
Ok { chrom ; chrom_start ; chrom_end ; name ; score ; others }
let item_of_line l =
let open Result in
match Line.split l ~on:'\t' with
| chrom :: chrom_start :: chrom_end :: name :: score :: others ->
Field.(parse ~ctx:"chrom_start" positive_int) chrom_start >>= fun chrom_start ->
Field.(parse ~ctx:"chrom_end" positive_int) chrom_end >>= fun chrom_end ->
Field.(parse ~ctx:"score" (bounded_int ~lo:0 ~hi:1000)) score >>= fun score ->
Ok { chrom ; chrom_start ; chrom_end ; name ; score ; others }
| _ -> Error "Expected at least 5 fields separated by tab characters"
let line_of_item = Bed5_raw.line_of_item
end