pdb.bend checks
raw source on the hub · import 0xdf198d67659100c90a58ecd6b01d034d/pdb.bend as Pdb
3 imports
import Base import ./geom.bend as G import ./protein.bend as P
Definitions
def pdb_slice source · line 23 · raw
@s:String -> @start:Nat -> @len:Nat -> String
Fixed-column slice: 0-based start, length.
def is_atom_line source · line 26 · raw
@line:String -> Bool
def tlines_go source · line 31 · raw
@s:String -> @cur:String -> @acc:List<&2, String> -> List<&2, String>
Tail-recursive lines(): single self-call in tail position, so long files do not grow the machine stack (String.split recurses per character).
def tlines source · line 40 · raw
@s:String -> List<&2, String>
def atom_lines_go source · line 46 · raw
@lines:List<&2, String> -> @acc:List<&2, String> -> List<&2, String>
ATOM lines up to (excluding) the first ENDMDL. Decided by matching the first six characters literally, so no computed Bool is ever matched. Tail-recursive over lines for the same stack reason as tlines.
def atom_lines source · line 59 · raw
@lines:List<&2, String> -> List<&2, String>
def is_conect_line source · line 62 · raw
@line:String -> Bool
def conect_lines source · line 66 · raw
@lines:List<&2, String> -> List<&2, String>
CONECT lines anywhere in the file (they follow ENDMDL in practice).
def pow10 source · line 78 · raw
@n:Nat -> U32
Powers of ten for the fractional scale.
def f32_apply_sign source · line 85 · raw
@neg:Bool -> @v:F32 -> F32
def f32_combine source · line 92 · raw
@neg:Bool -> @iv:U32 -> @fv:U32 -> @sc:U32 -> F32
def parse_f32_frac source · line 95 · raw
@neg:Bool -> @iv:U32 -> @f:Maybe<&2, U32> -> @sc:U32 -> Maybe<&2, F32>
def parse_f32_num source · line 102 · raw
@neg:Bool -> @i:Maybe<&2, U32> -> @fp:String -> @flen:Nat -> Maybe<&2, F32>
def parse_f32_int source · line 109 · raw
@neg:Bool -> @ip:String -> @+fp:String -> Maybe<&2, F32>
def parse_f32_split source · line 112 · raw
@neg:Bool -> @parts:List<&2, String> -> Maybe<&2, F32>
def parse_f32_stripped source · line 123 · raw
@p:Pair(Bool, String) -> Maybe<&2, F32>
def strip_sign_kept source · line 128 · raw
@plus:Bool -> @h:Char -> @t:String -> Pair(Bool, String)
def strip_sign_plus source · line 135 · raw
@+h:Char -> @t:String -> Pair(Bool, String)
def strip_sign_if source · line 138 · raw
@dash:Bool -> @h:Char -> @t:String -> Pair(Bool, String)
def strip_sign_go source · line 145 · raw
@+h:Char -> @t:String -> Pair(Bool, String)
def strip_sign source · line 148 · raw
@s:String -> Pair(Bool, String)
def parse_f32 source · line 156 · raw
@s:String -> Maybe<&2, F32>
Decimal floats: optional sign, digits, optional '.', digits.
def elem_1 source · line 160 · raw
@h:Char -> U32
Element symbol -> atomic number; unknown -> 0.
def elem_2 source · line 187 · raw
@h:Char -> @h2:Char -> U32
def elem_no_1 source · line 208 · raw
@h:Char -> @t:String -> U32
def elem_no source · line 215 · raw
@s:String -> U32
def elem_from_name source · line 222 · raw
@n:String -> U32
def elem_of_go source · line 229 · raw
@e:String -> @n:String -> U32
def elem_of source · line 236 · raw
@raw_elem:String -> @raw_name:String -> U32
def chain_u32 source · line 239 · raw
@s:String -> U32
def parse_atom_z source · line 248 · raw
@serial:U32 -> @ch:U32 -> @seq:Nat -> @x:F32 -> @y:F32 -> @mz:Maybe<&2, F32> -> @elem_s:String -> @name_s:String -> Maybe<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>
One ATOM line -> (chain, seq, atom). None{} when any field fails. Threaded bottom-up: each helper matches one Maybe and passes the rest on.
def parse_atom_y source · line 255 · raw
@serial:U32 -> @ch:U32 -> @seq:Nat -> @x:F32 -> @my:Maybe<&2, F32> -> @zs:String -> @elem_s:String -> @name_s:String -> Maybe<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>
def parse_atom_x source · line 262 · raw
@serial:U32 -> @ch:U32 -> @seq:Nat -> @mx:Maybe<&2, F32> -> @ys:String -> @zs:String -> @elem_s:String -> @name_s:String -> Maybe<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>
def parse_atom_seq source · line 269 · raw
@serial:U32 -> @ch:U32 -> @ms:Maybe<&2, Nat> -> @xs:String -> @ys:String -> @zs:String -> @elem_s:String -> @name_s:String -> Maybe<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>
def parse_atom_chain source · line 276 · raw
@serial:U32 -> @chain_s:String -> @seq_s:String -> @xs:String -> @ys:String -> @zs:String -> @elem_s:String -> @name_s:String -> Maybe<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>
def parse_atom_serial source · line 279 · raw
@ms:Maybe<&2, U32> -> @chain_s:String -> @seq_s:String -> @xs:String -> @ys:String -> @zs:String -> @elem_s:String -> @name_s:String -> Maybe<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>
def parse_atom_fields source · line 286 · raw
@serial_s:String -> @chain_s:String -> @seq_s:String -> @xs:String -> @ys:String -> @zs:String -> @elem_s:String -> @name_s:String -> Maybe<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>
def parse_atom_line source · line 289 · raw
@+line:String -> Maybe<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>
def conect_p4 source · line 293 · raw
@s0:U32 -> @m4:Maybe<&2, U32> -> List<&1, Pair(U32, U32)>
One CONECT line -> [(s0, si)] bonds for each partner present.
def conect_p3 source · line 300 · raw
@+s0:U32 -> @m3:Maybe<&2, U32> -> @m4:Maybe<&2, U32> -> List<&1, Pair(U32, U32)>
def conect_p2 source · line 307 · raw
@+s0:U32 -> @m2:Maybe<&2, U32> -> @m3:Maybe<&2, U32> -> @m4:Maybe<&2, U32> -> List<&1, Pair(U32, U32)>
def conect_p1 source · line 314 · raw
@+s0:U32 -> @m1:Maybe<&2, U32> -> @m2:Maybe<&2, U32> -> @m3:Maybe<&2, U32> -> @m4:Maybe<&2, U32> -> List<&1, Pair(U32, U32)>
def conect_assemble source · line 321 · raw
@m0:Maybe<&2, U32> -> @m1:Maybe<&2, U32> -> @m2:Maybe<&2, U32> -> @m3:Maybe<&2, U32> -> @m4:Maybe<&2, U32> -> List<&1, Pair(U32, U32)>
def parse_conect_line source · line 328 · raw
@+line:String -> List<&1, Pair(U32, U32)>
def collect_extend source · line 334 · raw
@m:Maybe<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))> -> @st:Pair(List<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>, Nat) -> Pair(List<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>, Nat)
Collect parsed atoms plus the skipped-line count. Tail-recursive: the extend step builds both outcomes as data (no match, no cycle) and the single self-call runs on the tail.
def collect_finish source · line 345 · raw
@st:Pair(List<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>, Nat) -> Pair(List<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>, Nat)
def collect_go source · line 350 · raw
@lines:List<&2, String> -> @st:Pair(List<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>, Nat) -> Pair(List<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>, Nat)
def collect_atoms source · line 357 · raw
@lines:List<&2, String> -> Pair(List<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>, Nat)
def append_conect source · line 360 · raw
@a:List<&1, Pair(U32, U32)> -> @b:List<&1, Pair(U32, U32)> -> List<&1, Pair(U32, U32)>
def conect_pairs source · line 367 · raw
@lines:List<&2, String> -> List<&1, Pair(U32, U32)>
def group_res_go source · line 379 · raw
@items:List<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))> -> @+cur_c:U32 -> @+cur_s:Nat -> @+cur_as:List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom> -> @+acc_c:List<&2, U32> -> @+acc_r:List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Residue> -> Pair(List<&2, U32>, List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Residue>)
Pass 1: consecutive equal (chain, seq) merge. Chains and residues run in parallel Data lists: a pair accumulator would not be reusable (+ needs Data), so the two stay aligned and are zipped after (zip_chains). Branchless: both next-states are built as data and picked, with one self-call on the tail, so no helper cycle is needed.
def group_residues source · line 389 · raw
@items:List<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))> -> Pair(List<&2, U32>, List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Residue>)
def zip_chains source · line 398 · raw
@cs:List<&2, U32> -> @rs:List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Residue> -> List<&1, Pair(U32, 0xdf198d67659100c90a58ecd6b01d034d/protein.Residue)>
Zip the parallel chain/residue lists back into pairs (aligned by construction; extra elements on either side are dropped).
def group_chain_go source · line 410 · raw
@items:List<&1, Pair(U32, 0xdf198d67659100c90a58ecd6b01d034d/protein.Residue)> -> @+cur_c:U32 -> @+cur_rs:List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Residue> -> @+acc:List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Chain> -> List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Chain>
Pass 2: consecutive equal chains merge into Chain.
def group_chains_zip source · line 419 · raw
@items:List<&1, Pair(U32, 0xdf198d67659100c90a58ecd6b01d034d/protein.Residue)> -> List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Chain>
def group_chains source · line 426 · raw
@cs:List<&2, U32> -> @rs:List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Residue> -> List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Chain>
def parse_pdb_group source · line 430 · raw
@g:Pair(List<&2, U32>, List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Residue>) -> @n:Nat -> Pair(0xdf198d67659100c90a58ecd6b01d034d/protein.Complex, Nat)
Whole file -> (Complex, skipped lines).
def parse_pdb_collect source · line 435 · raw
@p:Pair(List<&1, Pair(U32, Pair(Nat, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom))>, Nat) -> Pair(0xdf198d67659100c90a58ecd6b01d034d/protein.Complex, Nat)
def parse_pdb source · line 440 · raw
@text:String -> Pair(0xdf198d67659100c90a58ecd6b01d034d/protein.Complex, Nat)
def complex_of source · line 443 · raw
@p:Pair(0xdf198d67659100c90a58ecd6b01d034d/protein.Complex, Nat) -> 0xdf198d67659100c90a58ecd6b01d034d/protein.Complex
def skipped_of source · line 448 · raw
@p:Pair(0xdf198d67659100c90a58ecd6b01d034d/protein.Complex, Nat) -> Nat
def first_elem_go source · line 453 · raw
@xs:List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom> -> Maybe<&2, U32>
def first_elem source · line 460 · raw
@cx:0xdf198d67659100c90a58ecd6b01d034d/protein.Complex -> Maybe<&2, U32>
def demo_text source · line 464 · raw
String
Two-line ALA snippet for laws and smoke tests.
def demo_bad_text source · line 468 · raw
String
A bad serial ("X") so the second line skips.
def finish_read source · line 471 · raw
@fr:Pair(File, Result<&1, &1, Pair(U32, String), String>) -> IO(Pair(0xdf198d67659100c90a58ecd6b01d034d/protein.Complex, Nat))
def load_pdb_file source · line 480 · raw
@path:String -> IO(Pair(0xdf198d67659100c90a58ecd6b01d034d/protein.Complex, Nat))
Whole file from disk -> (Complex, skipped lines). Reads at most 1 MiB.
def pad_left source · line 491 · raw
@+s:String -> @w:Nat -> String
def pad_right source · line 494 · raw
@+s:String -> @w:Nat -> String
def pad_zero source · line 497 · raw
@+s:String -> @w:Nat -> String
def fmt_u32 source · line 500 · raw
@w:Nat -> @x:U32 -> String
def fmt_nat source · line 503 · raw
@w:Nat -> @n:Nat -> String
def fmt_frac3 source · line 506 · raw
@f:F32 -> String
def fmt_abs source · line 509 · raw
@+x:F32 -> F32
def fmt_f83_sign source · line 512 · raw
@sgn:String -> @+ax:F32 -> String
def fmt_f83 source · line 515 · raw
@+x:F32 -> String
def elem_sym source · line 518 · raw
@e:U32 -> String
def write_atom_line source · line 561 · raw
@serial:U32 -> @name4:String -> @chain1:String -> @seq:Nat -> @x:F32 -> @y:F32 -> @z:F32 -> @elem2:String -> String
def write_atom_pos source · line 564 · raw
@serial:U32 -> @+elem:U32 -> @pos:0xdf198d67659100c90a58ecd6b01d034d/geom.Vec3 -> @chain1:String -> @seq:Nat -> String
def write_atom source · line 569 · raw
@h:0xdf198d67659100c90a58ecd6b01d034d/protein.Atom -> @chain1:String -> @seq:Nat -> String
def write_atoms source · line 574 · raw
@xs:List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Atom> -> @+chain1:String -> @+seq:Nat -> List<&2, String>
def append_lines source · line 581 · raw
@a:List<&2, String> -> @b:List<&2, String> -> List<&2, String>
def write_residue source · line 588 · raw
@r:0xdf198d67659100c90a58ecd6b01d034d/protein.Residue -> @chain1:String -> List<&2, String>
def write_residues source · line 593 · raw
@rs:List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Residue> -> @+chain1:String -> List<&2, String>
def write_chain source · line 600 · raw
@c:0xdf198d67659100c90a58ecd6b01d034d/protein.Chain -> List<&2, String>
def write_chains source · line 605 · raw
@cs:List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Chain> -> List<&2, String>
def complex_chains source · line 612 · raw
@k:0xdf198d67659100c90a58ecd6b01d034d/protein.Complex -> List<&2, 0xdf198d67659100c90a58ecd6b01d034d/protein.Chain>
def write_complex source · line 617 · raw
@k:0xdf198d67659100c90a58ecd6b01d034d/protein.Complex -> String
def finish_write source · line 620 · raw
@fr:Pair(File, Result<&1, &1, Pair(U32, String), Unit>) -> IO(Unit)
def write_text_file source · line 628 · raw
@path:String -> @text:String -> IO(Unit)
def save_pdb_file source · line 634 · raw
@path:String -> @cx:0xdf198d67659100c90a58ecd6b01d034d/protein.Complex -> IO(Unit)
def finish_bonds source · line 637 · raw
@fr:Pair(File, Result<&1, &1, Pair(U32, String), String>) -> IO(List<&1, Pair(U32, U32)>)
def load_pdb_bonds source · line 646 · raw
@path:String -> IO(List<&1, Pair(U32, U32)>)
CONECT bonds from disk. A second full read; callers flatten once.
def finish_text source · line 652 · raw
@fr:Pair(File, Result<&1, &1, Pair(U32, String), String>) -> IO(String)
def load_text_file source · line 661 · raw
@path:String -> IO(String)
Raw file text (for template atom collection).