Suppose we have a types:
type ABC is (A, B, C);
type BAC is (B, A, C);
type CBA is (C, B, A);
Is there any way to declare generic package with parameter Order:
generic
type Order is ...
package Pkg
type Value_Type is ...
type Value_Type_Array is array (Order) of Value_Type;
end Pkg;
that after instantiation I can have 3 different types:
AA : Package_ABC.Value_Type_Array;
BB : Package_BAC.Value_Type_Array;
CC : Package_CBA.Value_Type_Array;
Update: I forgot to say that I want use values of those types in the program. If we say that X, Y and Z are variables of type Value_Type:
begin
AA (A) := X;
AA (B) := Y;
AA (C) := Z;
...
BB (B) := X;
BB (A) := Y;
BB (C) := Z;
...
CC (C) := X;
CC (B) := Y;
CC (A) := Z;
...
end;
Enumeration types are discrete types (like integer types), so you would do:
generic
type Order is (<>);
package Pkg
Related
Is it possible to declare multiple variable bindings in one line in SML? For example, I have the following:
let
val m1 = [1]
val m2 = [2]
val m3 = [3]
in
{...}
end
I would like to condense this down to something like
let
val m1 = [1], m2 = [2], m3 = [3]
in
{...}
end
This syntax doesn't work, but is there a way to declare multiple variable bindings in one line like this?
Here are two ways:
- let val x = 1 val y = 5 in x + y end;
val it = 6 : int
- let val x = 1 and y = 5 in x + y end;
val it = 6 : int
I personally find the slight abuse of and more readable.
However, I think the "destructuring bind" method is more common than either of these, since it's also more generally useful.
- let val (x, y) = (1,5) in x + y end;
val it = 6 : int
- fun f x = (x, x + 2, x + 3);
val f = fn : int -> int * int * int
- let val (x, y, z) = f 3 in x + z end;
val it = 9 : int
You could create a tuple and immediately destructure it.
let
val (m1, m2, m3) = ([1], [2], [3])
in
...
end
Below is SML code to compute a definite integral using the trapezoidal method given input f=unary function, a & b=range to take integral under, and n=number of sub-intervals to divide the range into.
fun integrate f a b n =
let val w = (b - a) / (real n)
fun genBlock c = let val BB = f c
val SB = f (c+w)
in (BB + SB) * w / 2.0
end
fun sumSlice 0 c acc = acc
| sumSlice n c acc = sumSlice (n-1) (c+w) (acc + (genBlock c))
in sumSlice n a 0.0
end
Problem is I can't figure out for the life of me how to define a function (say X cubed) and feed it to this function with a,b, and n. Here's a screenshot of me trying and receiving an error:
In this picture I define cube x =xxx and show it works, then try to feed it to the integrate function to no avail.
The error message is pretty specific: integrate is expecting a function of type real -> real but you defined a function, cube, of type int -> int.
There are a couple of things you can do:
1) Add a type annotation to the definition of cube:
- fun cube x:real = x*x*x;
val cube = fn : real -> real
And then:
- integrate cube 0.0 5.0 5;
val it = 162.5 : real
2) You can dispense with defining cube as a named function and just pass the computation as an anonymous function. In this case, SML's type inference mechanism gives the function x => x*x*x the intended type:
- integrate (fn x => x*x*x) 0.0 5.0 5;
val it = 162.5 : real
An exercise questions asks for an explanation as to why this won't work. Obviously from running the code I see that it doesn't, but I don't see in this case why. The error doesn't clarify much!
# let (+) x y z = x + y + z in 5 + 6 7;;
Error: This expression has type int
This is not a function; it cannot be applied.
Thanks!
Lets go step-by-step. Fire a REPL and type:
# let (+) x y z = x + y + z;;
val ( + ) : int -> int -> int -> int = <fun>
We can interpret this int -> int -> int -> int as an infix + operator that takes two ints and returns an int -> int function.
Lets check that:
# let f = 5+6;;
val f : int -> int = <fun>
# f 7;;
- : int = 18
That's every step of your intended program working.
The issue with your code is that this doesn't work:
# 5+6 7;;
Error: This expression has type int
This is not a function; it cannot be applied.
That happens because function application has a precedence over + operator. (In fact, function application has the strongest precedence in OCaml.) So adding the brackets, fixes it (you'll need to restart the toplevel):
# let (+) x y z = x + y + z in (5+6) 7;;
- : int = 18
I am trying to compute a Log Likelihood score for occurrence of pairs of words in text and am getting the same anomalous results in my Delphi implementation which I've derived from Java and Python sources found online. Ted Dunning who published on this source in 1993 gives these results for one particular pair:
K11 (AB, ie joint frequency) = 110,
K12 (word A without B nearby) = 2442,
K21 (B without A nearby) = 111
K22 (number of words other than A or B in the text) = 29114
and gives the desired result as 270.72
Dunning also gives an implementation in R at
http://tdunning.blogspot.co.uk/2008/03/surprise-and-coincidence.html
Computing the log-likelihood ratio score (also known as G2) is very
simple, LLR = 2 sum(k) (H(k) - H(rowSums(k)) - H(colSums(k)))
where H is Shannon's entropy, computed as the sum of (k_ij / sum(k)) log (k_ij / sum(k)) . In R, this function is defined as
H = function(k) {N = sum(k) ; return (sum(k/N * log(k/N + (k==0)))}
but I do not know R and am unsure how to translate that to Pascal.
My translation attempts include these functions
function LnOK(x : integer): extended;
begin
if x<=0 then Result :=0
else Result := Ln(x);
end;
function Entropy2(a, b: Integer): extended;
begin
Result := LnOK(a + b) - LnOK(a) - LnOK(b);
end;
function Entropy4(a, b, c, d: Integer): extended;
begin
Result := LnOK(a + b + c + d) - LnOK(a) - LnOK(b) - LnOK(c) - LnOK(d);
end;
function Log_likelihood_from_Java(f1, f2, joint, total_tokens: Integer):
single;
var
k11, k12, k21, k22: Integer;
matrixEntropy, rowEntropy, colEntropy: extended;
begin
k11 := joint;
k12 := f2 - joint;
k21 := f1 - joint;
k22 := total_tokens - f1 - f2 + joint;
rowEntropy := Entropy2(k11 + k12, k21 + k22);
colEntropy := Entropy2(k11 + k21, k12 + k22);
matrixEntropy := Entropy4(k11, k12, k21, k22);
if (rowEntropy + colEntropy < matrixEntropy) then
Result := 0.0 // round off error
else
Result := 2.0 * (rowEntropy + colEntropy - matrixEntropy);
end;
The above returns 7.9419 instead of the desired 270.72 when it's called like this:
Log_likelihood_from_Java(2552, 221, 110, 31777);
Grateful for help!
I've found the issue in the translation of the LnOk function which should be as follows:
function LnOK(x: Integer): Extended;
begin
if x = 0 then
Result := 0
else
Result := x * Ln(x);
end;
Off topic
As a side note if I'm allowed, just to improve the coding style, you might prefer to overload the Entropy functions instead of calling them with different names:
function Entropy(a, b: Integer): Extended; overload;
begin
Result := LnOK(a + b) - LnOK(a) - LnOK(b);
end;
function Entropy(a, b, c, d: Integer): Extended; overload;
begin
Result := LnOK(a + b + c + d) - LnOK(a) - LnOK(b) - LnOK(c) - LnOK(d);
end;
I can't make any sense of the code that you wrote which bears no obvious relationship to the R code to which you linked. I did not make any attempt to reconcile these differences.
Here's a literal translation of the R code. The algorithm is much simpler written this way as I am sure you will agree.
{$APPTYPE CONSOLE}
uses
SysUtils, Math;
type
TVector2 = array [1..2] of Double;
TMatrix2 = array [1..2] of TVector2;
function rowSums(const M: TMatrix2): TVector2;
begin
Result[1] := M[1,1] + M[1,2];
Result[2] := M[2,1] + M[2,2];
end;
function colSums(const M: TMatrix2): TVector2;
begin
Result[1] := M[1,1] + M[2,1];
Result[2] := M[1,2] + M[2,2];
end;
function H(const k: array of Double): Double;
var
i: Integer;
N, kOverN: Double;
begin
N := Sum(k);
Result := 0.0;
for i := low(k) to high(k) do begin
kOverN := k[i]/N;
if kOverN>0.0 then begin
Result := Result + kOverN*Ln(kOverN);
end;
end;
end;
function LLR(const M: TMatrix2): Double;
var
k: array [1..4] of Double absolute M; // this is a little sneaky I admit
rs, cs: TVector2;
begin
rs := rowSums(M);
cs := colSums(M);
Result := 2.0*Sum(k)*(H(k) - H(rs) - H(cs));
end;
var
M: TMatrix2;
begin
M[1,1] := 110;
M[1,2] := 2442;
M[2,1] := 111;
M[2,2] := 29114;
Writeln(LLR(M));
end.
Output
2.70721876936232E+0002
I'm really more interested in the theoretical-set answer. So maybe I should ask int * int vs int + int. I interpret int * int as a tuple with cardinal of int squared as the number of combinations.
If you want to find out more about the theory, you can search for information about product types (tuples are a basic case, records are labeled products) and sum types (the Choice<..> type in F# is a basic case, discriminated unions are labeled sum types).
The set-theoretical interpretation is that product types correspond to product of sets and sum types correspond to a union (more precisely to a disjoint union - because they are labeled).
So, assuming that [| T |] is a set representing values of a type T:
[| T1 * T2 |] = { (v1, v2) | v1 ∈ [| T1 |], v2 ∈ [| T2 |] }
[| T1 + T2 |] = { (1, v) | v ∈ [| T1 |] } ∪ { (2, v) | v ∈ [| T2 |] }
A simpler version of the + operation would be just union, but that only makes sense when the two types have distinct values (and so you can distinguish between without the labels):
[| T1 + T2 |] = [| T1 |] ∪ [| T2 |]
This is actually quite fun, because you can find out that many of the standard algebraic laws will work for types too. For example, distributivity says that: (a + b) * c = (a * c) + (b * c). This works for types too and it means that the following two are equivalent:
type AorB = A of int | B of string // int + string
type AorBandC = AorB * float // (int + string) * float
type AandC = int * float // int * float
type BandC = string * float // string * float
type AandCorBandC = AC of AandC | BC of BandC // (int * float) + (string * float)
You can write a pair of functions that will map between the values of AorBandC and AandCorBandC. In fact, you can go even wilder and even differentiate types. This is a bit crazy, but you asked for a theory: http://www.cs.nott.ac.uk/~txa/publ/jpartial.pdf
Yes, record types are just like tuple types, except that their elements have names. As the F#/ML syntax for tuples types suggests, a tuple of type A * B * C * ... has |A| * |B| * |C| * ... possible values. Likewise, you are also right that a discriminated union | N1 of A | N2 of B | ... has |A| + |B| + ... possible values. You didn't mention it, but function types correspond to exponentiation: A -> B has |B||A| inhabitants.