. — Inner product

X f.g Y pairs items with g, then reduces with f. It contracts the last axis of X with the first of Y.

1 2 3+.×4 5 6      ⍝ 32
[1 0⋄0 1]+.×2 2⍴⍳4 ⍝ 2 2⍴⍳4

Singleton contraction axes extend. Empty contractions use the reduction identity. g⊗ is outer product.

After an array, .name reads a keyed array value: T.name is "name"⊃T. It also works as an assignment target. Plain assignment creates missing records along the path.

T←["n":1 "addr":["city":"LA"]]
T.addr.city        ⍝ "LA"
T.n+←1 ⋄ T.n       ⍝ 2

After an array, . followed by brackets indexes it through Index: x.[I] is [I]⌷x. Each bracket item indexes one axis. The positions on one axis form one item, as in m.[[2 0]]. Dot indexing binds as tightly as .name and needs no parentheses inside a larger expression. Paths chain from left to right. The array is evaluated before the index.

m←3 4⍴⍳12
m.[1 2]            ⍝ 6
m.[[2 0]]          ⍝ [8 9 10 11⋄0 1 2 3]
m.[⍳2 ¯1]          ⍝ 3 7
9,m.[0 1],3        ⍝ 9 1 3

After a keyed vector T, T.(expr) evaluates expr with each key of T as a name for its item. Names that aren’t keys resolve in the current scope, and a key hides a name it shares. A key that holds a function binds as a function. Assignments inside the parentheses stay there, and leave T and the current scope unchanged. Execute does the same for code in text: T⍎"price×qty" is T.(price×qty). A scope doesn’t map over an array of records. Write {⍵.(expr)}¨recs for that.

T←["price":2 3;"qty":10 20]
T.(price×qty)              ⍝ 20 60
rate←0.5 ⋄ T.(price×rate)  ⍝ 1 1.5
r←T.(price←0) ⋄ T.price    ⍝ 2 3

A dot followed by a digit is a decimal point: .2 is a number. To index position 2, write v.[2] or the subscript v₂. Assignment to a dot path goes through ⌷ and adds missing keys.

v←10 20 30
v.[[2 0]]←7 8 ⋄ v  ⍝ 8 20 7