1 import Base 2 3 # A statically shaped product. Pairing readers preserves one buffer owner. 4 type Twin<-Element: Data> is Data: 5 Twin{first: Element,second: Element} 6 7 # Static product composition also lifts an operation to any pair of elements. 8 # Nesting this template gives wider products without another arithmetic kernel. 9 def zip_map(~Element: Data,~Context: Data,~combine: Element -> Element -> Context -> Element, 10 left: Twin,right: Twin,context: Context) -> Twin: 11 Twin{left_first,left_second} = left 12 Twin{right_first,right_second} = right 13 +context = context 14 Twin{combine(left_first,right_first,context),combine(left_second,right_second,context)} 15 16 def finish_pair(~State: Type,~Element: Data,first: Element,result: State & Element) -> State & Twin: 17 (state,second) = result 18 (state,Twin{first,second}) 19 20 def read_second( 21 ~State: Type,~Context: Data,~Element: Data,~Index: Data, 22 ~read: State -> Context -> Index -> State & Element, 23 result: State & Element,context: Context,index: Index 24 ) -> State & Twin: 25 (state,first) = result 26 finish_pair(~State,~Element,first,read(state,context,index)) 27 28 def read_at( 29 ~State: Type,~Context: Data,~Element: Data,~Index: Data, 30 ~read: State -> Context -> Index -> State & Element, 31 state: State,+context: Context,first: Index,second: Index 32 ) -> State & Twin: 33 read_second(~State,~Context,~Element,~Index,~read,read(state,context,first),context,second) 34 35 def read_pair( 36 ~State: Type,~Context: Data,~Element: Data, 37 ~read: State -> Context -> Nat -> State & Element,~stride: Nat, 38 state: State,context: Context,index: Nat 39 ) -> State & Twin: 40 +context = context 41 +index = index 42 read_at(~State,~Context,~Element,~Nat,~read,state,context,index,Nat.add(index,stride))