~/bend-docscommunity

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).