100 likes | 195 Views
More type systems. Physical units. A unit expression is defined by following grammar u , v := b | 1 | u * v | u -1 where u , v are unit expressions themselves and b is a base unit: b := m | kg | s | A | K | cd | mol
E N D
Physical units A unit expression is defined by following grammar u, v := b | 1 | u * v | u-1 where u, v are unit expressions themselves and b is a base unit: b := m | kg | s | A | K | cd | mol You may use B to denote the set of the unit types B = { m, kg, s, A, K, cd, mol} For readability, we use the syntactic sugar u^n= u * … * u if n > 0 1 if n = 0 u-1 * … * u-1 if n < 0 and u/v = u * v-1
Physical units a) Give the type rules for the arithmetic operations + , *, /, √, sin, abs. Assume that the trigonometric functions take as argument radians, which are dimensionless (since they are defined as the ratio of arc length to radius). You can denote that a variable is dimensionless by Γ˫ e : 1 Γ˫a : U Γ˫b : U Γ˫a : U Γ˫b : V Γ˫a + b : U Γ˫a * b : U*V Γ˫a : U*U Γ˫a : U Γ˫b : V Γ˫a / b : U/V Γ˫√a: U Γ˫a : U Γ˫a : 1 Γ˫abs(a): U Γ˫sin(a): 1
Physical units b) The unit expressions as defined above are strings, so that e.g.(s^4*m^2)/(s^2*m^3) ≠ s^2*mhowever physically these units match. Define a procedure on the unit expressions such that your type rules type check expressions, whenever they are correct according to physics. traitPUnit caseclass Times(a: PUnit, b: PUnit) extendsPUnit caseclass Inverse(a: PUnit) extendsPUnit caseclass SI(v: String) extendsPUnit caseclass One extendsPUnit
Physical units defnumerator(t: PUnit): List[SI] = t match { case Times(a, b) => numerator(a) ++ numerator(a) case Inverse(a) => denominator(a) case SI(_) => List(t) case One => Nil } defdenominator(t: PUnit): List[SI] = t match { case Times(a, b) => denominator(a) ++ denominator(a) case Inverse(a) => numerator(a) case SI(_) => List() case One => Nil }
Physical units defsimplify(t: PUnit): PUnit = { val num = numerator(t) val den = denominator(t) val inter = numintersect den val num2 = (num -- inter).sortBy(_.v) val den2 = (den – inter).sortBy(_.v) val a = (One /: num2) { case (res, p) => Times(res, p)} val b = (One /: den2) { case (res, p) => Times(res, p)} Times(num2, Inverse(denum2)) } Γ˫a : U Γ˫a : (U*U)-1 Γ˫a : simplify(U) Γ˫√a: U-1
Physical units c)Determine the type of Tin the following code fragment. The values in angle brackets give the unit type expressions of the variables and Piis the usual constant π in the Scala math library. Give the full type derivation tree using your rules from a) and b), i.e. the tree that infers the types of the variables R, w, T. val x: <m> = 800 val y: <m> = 6378 val g: <m/(s*s)> = 9.8 val R = x + y val w = sqrt(g/R) val T = (2 * Pi) / w
Physical units valx: <m> = 800 val y: <m> = 6378 val g: <m/(s*s)> = 9.8 val R = x + y val w = sqrt(g/R) val T = (2 * Pi) / w Γ˫x : m Γ˫y : m Γ˫x + y : m Γ˫R : m Γ˫g : m/(s*s) Γ˫g / R : (m/(s*s)) / m Γ˫g / R : 1/(s*s) Γ˫2 : 1 Γ˫π: 1 Γ˫g / R : (1/s)*(1/s) Γ˫2*π : 1*1 Γ˫ √(g/R): 1/s Γ˫ w: 1/s Γ˫2*π : 1 Γ˫ (2*π / w): 1/(1/s) Γ˫ (2*π / w): s
Physical units d) Consider the following function that computes the Coulomb force, and suppose for now that the compiler can parse the type expressions: defcoulomb(k: <(N*m)/(C*C)>, q1: <C>, q2: <C>, r: <m>): <N> { return (k* q1 * q2)/(r*r) } The derived types are C = A*s and N = kg*m / s^2. Does the code type check? Justify your answer rigorously. No: Expected N, got N/m. Type tree for return expression.
Physicalunits Γ˫q1: C Γ˫k: N*m/(C*C) Γ˫k*q1: N*m/(C*C) * C Γ˫q2: C Γ˫k*q1: N*m/C Γ˫ r: m Γ˫ r: m Γ˫k*q1*q2: (N*m/C * C) Γ˫ r*r: m*m Γ˫k*q1*q2: m*N Γ˫ k*q1*q2/(r*r) : m*N / (m*m) Γ˫ k*q1*q2/(r*r) : N/m