Skip to content

Commit

Permalink
Finish Int
Browse files Browse the repository at this point in the history
  • Loading branch information
julianhyde committed Sep 26, 2024
1 parent 62937cf commit 7ee82dd
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 35 deletions.
38 changes: 33 additions & 5 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,32 @@ Exception:
| General.op o | (β → γ) (α → β) → α → γ | "f o g" is the function composition of `f` and `g`. Thus, `(f o g) a` is equivalent to `f (g a)`. |
| Interact.use | string → unit | "use f" loads source text from the file named `f`. |
| Interact.useSilently | string → unit | "useSilently f" loads source text from the file named `f`, without printing to stdout. |
| Int op * | int * int → int | "i * j" is the product of `i` and `j`. It raises Overflow when the result is not representable. |
| Int op + | int * int → int | "i + j" is the sum of `i` and `j`. It raises Overflow when the result is not representable. |
| Int op - | int * int → int | "i - j" is the difference of `i` and `j`. It raises Overflow when the result is not representable. |
| Int op div | int * int → int | "i div j" returns the greatest integer less than or equal to the quotient of i by j, i.e., `floor(i / j)`. It raises Overflow when the result is not representable, or Div when `j = 0`. Note that rounding is towards negative infinity, not zero. |
| Int op mod | int * int → int | "i mod j" returns the remainder of the division of i by j. It raises Div when `j = 0`. When defined, `(i mod j)` has the same sign as `j`, and `(i div j) * j + (i mod j) = i`. |
| Int op < | int * int → bool | "x < y" returns true if x is less than y. Return false on unordered arguments, i.e., if either argument is NaN, so that the usual reversal of comparison under negation does not hold, e.g., `a < b` is not the same as `not (a >= b)`. |
| Int op <= | int * int → bool | As "<" |
| Int op > | int * int → bool | As "<" |
| Int op >= | int * int → bool | As "<" |
| Int op ~ | int → int | "~ i" returns the negation of `i`. |
| Int.abs | int → int | "abs i" returns the absolute value of `i`. |
| Int.compare | int * int → order | "compare (i, j)" returns `LESS`, `EQUAL`, or `GREATER` according to whether its first argument is less than, equal to, or greater than the second. |
| Int.fromInt, int | int → int | "fromInt i" converts a value from type `int` to the default integer type. Raises Overflow if the value does not fit. |
| Int.fromString | string → int option | "fromString s" scans a `int` value from a string. Returns `SOME(r)` if a `int` value can be scanned from a prefix of `s`, ignoring any initial whitespace; otherwise, it returns `NONE`. Equivalent to `StringCvt.scanString (scan StringCvt.DEC)`. |
| Int.max | int * int → int | "max (i, j)" returns the larger of the arguments. |
| Int.maxInt | int | "maxInt" is the maximal (most positive) integer representable by `int`. If a value is `NONE`, `int` can represent all positive integers, within the limits of the heap size. If `precision` is `SOME(n)`, then we have `maxInt` = 2<sup>(n-1)</sup> - 1. |
| Int.min | int * int &rarr; int | "min (i, j)" returns the smaller of the arguments. |
| Int.minVal | int | "minPos" is the minimal (most negative) integer representable by `int`. If a value is `NONE`, `int` can represent all negative integers, within the limits of the heap size. If `precision` is `SOME(n)`, then we have `minInt` = -2<sup>(n-1)</sup>. |
| Int.mod | int * int &rarr; int | "mod (i, j)" returns the remainder of the division of `i` by `j`. It raises `Div` when `j = 0`. When defined, `(i mod j)` has the same sign as `j, and `(i div j) * j + (i mod j) = i`. |
| Int.precision | int | "precision" is the precision. If `SOME(n)`, this denotes the number `n` of significant bits in type `int`, including the sign bit. If it is `NONE`, int has arbitrary precision. The precision need not necessarily be a power of two. |
| Int.quot | int * int &rarr; int | "quot (i, j)" returns the truncated quotient of the division of `i` by `j`, i.e., it computes `(i / j)` and then drops any fractional part of the quotient. It raises `Overflow` when the result is not representable, or `Div` when `j = 0`. Note that unlike `div`, `quot` rounds towards zero. In addition, unlike `div` and `mod`, neither `quot` nor `rem` are infix by default; an appropriate infix declaration would be `infix 7 quot rem`. This is the semantics of most hardware divide instructions, so `quot` may be faster than `div`. |
| Int.rem | int * int &rarr; int | "rem (i, j)" returns the remainder of the division of `i` by `j`. It raises `Div` when `j = 0`. `(i rem j)` has the same sign as i, and it holds that `(i quot j) * j + (i rem j) = i`. This is the semantics of most hardware divide instructions, so `rem` may be faster than `mod`. |
| Int.sameSign | int * int &rarr; bool | "sameSign (i, j)" returns true if `i` and `j` have the same sign. It is equivalent to `(sign i = sign j)`. |
| Int.sign | int &rarr; int | "sign i" returns ~1, 0, or 1 when `i` is less than, equal to, or greater than 0, respectively. |
| Int.toInt | int &rarr; int | "toInt i" converts a value from the default integer type to type `int`. Raises Overflow if the value does not fit. |
| Int.toString | int &rarr; string | "toString i" converts a `int` into a `string`; equivalent to `(fmt StringCvt.DEC r)`. |
| List.nil | &alpha; list | "nil" is the empty list. |
| List.null | &alpha; list &rarr; bool | "null l" returns `true` if the list `l` is empty. |
| List.length | &alpha; list &rarr; int | "length l" returns the number of elements in the list `l`. |
Expand Down Expand Up @@ -355,7 +381,7 @@ Exception:
| Option.composePartial | (&alpha; &rarr; &beta; option) * (&gamma; &rarr; &alpha; option) &rarr; &gamma; &rarr; &beta; option | "composePartial (f, g) a" returns `NONE` if `g(a)` is `NONE`; otherwise, if `g(a)` is `SOME v`, returns `f(v)`. |
| Option.map | &alpha; &rarr; &beta;) &rarr; &alpha; option &rarr; &beta; option | "map f opt" maps `NONE` to `NONE` and `SOME v` to `SOME (f v)`. |
| Option.mapPartial | &alpha; &rarr; &beta; option) &rarr; &alpha; option &rarr; &beta; option | "mapPartial f opt" maps `NONE` to `NONE` and `SOME v` to `f(v)`. |
| Option.getOpt | &alpha; option * &alpha; &rarr; &alpha; | "getOpt (opt, a)" returns `v` if `opt` is `SOME(v)`; otherwise returns `a`. |
| Option.getOpt | &alpha; option * &alpha; &rarr; &alpha; | "getOpt (opt, a)" returns `v` if `opt` is `SOME (v)`; otherwise returns `a`. |
| Option.isSome | &alpha; option &rarr; bool | "isSome opt" returns `true` if `opt` is `SOME v`; otherwise returns `false`. |
| Option.filter | (&alpha; &rarr; bool) &rarr; &alpha; &rarr; &alpha; option | "filter f a" returns `SOME a` if `f(a)` is `true`, `NONE` otherwise. |
| Option.join | &alpha; option option &rarr; &alpha; option | "join opt" maps `NONE` to `NONE` and `SOME v` to `v`. |
Expand All @@ -377,7 +403,7 @@ Exception:
| Real.floor | real &rarr; int | "floor r" produces `floor(r)`, the largest int not larger than `r`. |
| Real.fromInt, real | int &rarr; real | "fromInt i" converts the integer `i` to a `real` value. If the absolute value of `i` is larger than `maxFinite`, then the appropriate infinity is returned. If `i` cannot be exactly represented as a `real` value, uses current rounding mode to determine the resulting value. |
| Real.fromManExp | {exp:int, man:real} &rarr; real | "fromManExp r" returns `{man, exp}`, where `man` and `exp` are the mantissa and exponent of r, respectively. |
| Real.fromString | string &rarr; real option | "fromString s" scans a `real` value from a string. Returns `SOME(r)` if a `real` value can be scanned from a prefix of `s`, ignoring any initial whitespace; otherwise, it returns `NONE`. This function is equivalent to `StringCvt.scanString scan`. |
| Real.fromString | string &rarr; real option | "fromString s" scans a `real` value from a string. Returns `SOME (r)` if a `real` value can be scanned from a prefix of `s`, ignoring any initial whitespace; otherwise, it returns `NONE`. This function is equivalent to `StringCvt.scanString scan`. |
| Real.isFinite | real &rarr; bool | "isFinite x" returns true if x is neither NaN nor an infinity. |
| Real.isNan | real &rarr; bool | "isNan x" returns true if x NaN. |
| Real.isNormal | real &rarr; bool | "isNormal x" returns true if x is normal, i.e., neither zero, subnormal, infinite nor NaN. |
Expand Down Expand Up @@ -438,8 +464,8 @@ Exception:
| Vector.collate |
| Vector.concat | &alpha; vector list &rarr; &alpha; vector | "concat l" returns the vector that is the concatenation of the vectors in the list `l`. Raises `Size` if the total length of these vectors exceeds `maxLen` |
| Vector.exists |
| Vector.find | (&alpha; &rarr; bool) &rarr; &alpha; vector &rarr; &alpha; option | "find f vec" applies `f` to each element `x` of the vector `vec`, from left to right, until `f(x)` evaluates to `true`. It returns `SOME(x)` if such an `x` exists; otherwise it returns `NONE`. |
| Vector.findi | (int * &alpha; &rarr; bool) &rarr; &alpha; vector &rarr; (int * &alpha;) option | "findi f vec" applies `f` to each element `x` and element index `i` of the vector `vec`, from left to right, until `f(i, x)` evaluates to `true`. It returns `SOME(i, x)` if such an `x` exists; otherwise it returns `NONE`. |
| Vector.find | (&alpha; &rarr; bool) &rarr; &alpha; vector &rarr; &alpha; option | "find f vec" applies `f` to each element `x` of the vector `vec`, from left to right, until `f(x)` evaluates to `true`. It returns `SOME (x)` if such an `x` exists; otherwise it returns `NONE`. |
| Vector.findi | (int * &alpha; &rarr; bool) &rarr; &alpha; vector &rarr; (int * &alpha;) option | "findi f vec" applies `f` to each element `x` and element index `i` of the vector `vec`, from left to right, until `f(i, x)` evaluates to `true`. It returns `SOME (i, x)` if such an `x` exists; otherwise it returns `NONE`. |
| Vector.foldl | (&alpha; * &beta; &rarr; &beta;) &rarr; &beta; &rarr; &alpha; vector &rarr; &beta; | "foldl f init vec" folds the function `f` over all the elements of vector `vec`, left to right, using the initial value `init` |
| Vector.foldli | (int * &alpha; * &beta; &rarr; &beta;) &rarr; &beta; &rarr; &alpha; vector &rarr; &beta; | "foldli f init vec" folds the function `f` over all the (index, element) pairs of vector `vec`, left to right, using the initial value `init` |
| Vector.foldr | (&alpha; * &beta; &rarr; &beta;) &rarr; &beta; &rarr; &alpha; vector &rarr; &beta; | "foldr f init vec" folds the function `f` over all the elements of vector `vec`, right to left, using the initial value `init` |
Expand All @@ -457,6 +483,8 @@ Not yet implemented

| Name | Type | Description |
| ---- | ---- | ----------- |
| Int.fmt | StringCvt.radix &rarr; int &rarr; string | "fmt radix i" returns a string containing a representation of i with #"~" used as the sign for negative numbers. Formats the string according to `radix`; the hexadecimal digits 10 through 15 are represented as #"A" through #"F", respectively. No prefix "0x" is generated for the hexadecimal representation. |
| Int.scan | scan radix getc strm | Returns `SOME (i,rest)` if an integer in the format denoted by `radix` can be parsed from a prefix of the character stream `strm` after skipping initial whitespace, where `i` is the value of the integer parsed and `rest` is the rest of the character stream. `NONE` is returned otherwise. This function raises `Overflow` when an integer can be parsed, but is too large to be represented by type `int`. |
| Real op != | real * real &rarr; bool | "x != y" is equivalent to `not o op ==` and the IEEE `?<>` operator. |
| Real op *+ | real * real * real &rarr; real | "*+ (a, b, c)" returns `a * b + c`. Its behavior on infinities follows from the behaviors derived from addition and multiplication. |
| Real op *- | real * real * real &rarr; real | "*- (a, b, c)" returns `a * b - c`. Its behavior on infinities follows from the behaviors derived from subtraction and multiplication. |
Expand All @@ -469,7 +497,7 @@ Not yet implemented
| Real.fromLarge | IEEEReal.rounding_mode &rarr; real &rarr; real | "toLarge r" converts a value of type `real` to type `LargeReal.real`. If `r` is too small or too large to be represented as a real, converts it to a zero or an infinity. |
| Real.fromLargeInt | IntInf.int &rarr; real | See "fromInt" |
| Real.nextAfter | real * real &rarr; real | "nextAfter (r, t)" returns the next representable real after `r` in the direction of `t`. Thus, if `t` is less than `r`, `nextAfter` returns the largest representable floating-point number less than `r`. |
| Real.scan | (char,'a) StringCvt.reader &rarr; (real,'a) StringCvt.reader | "scan getc strm" scans a `real` value from character source. Reads from ARG/strm/ using reader `getc`, ignoring initial whitespace. It returns `SOME(r, rest)` if successful, where `r` is the scanned `real` value and `rest` is the unused portion of the character stream `strm`. Values of too large a magnitude are represented as infinities; values of too small a magnitude are represented as zeros. |
| Real.scan | (char,'a) StringCvt.reader &rarr; (real,'a) StringCvt.reader | "scan getc strm" scans a `real` value from character source. Reads from ARG/strm/ using reader `getc`, ignoring initial whitespace. It returns `SOME (r, rest)` if successful, where `r` is the scanned `real` value and `rest` is the unused portion of the character stream `strm`. Values of too large a magnitude are represented as infinities; values of too small a magnitude are represented as zeros. |
| Real.toDecimal | real &rarr; IEEEReal.decimal_approx | "toDecimal r" converts a `real` to a decimal approximation |
| Real.toInt | real &rarr; IEEEReal.rounding_mode &rarr; int | "toInt mode x" converts the argument `x` to an integral type using the specified rounding mode. It raises `Overflow` if the result is not representable, in particular, if `x` is an infinity. It raises `Domain` if the input real is NaN. |
| Real.toLarge | real &rarr; real | "toLarge r" convert a value of type `real` to type `LargeReal.real`. |
Expand Down
33 changes: 17 additions & 16 deletions src/main/java/net/hydromatic/morel/eval/Codes.java
Original file line number Diff line number Diff line change
Expand Up @@ -327,12 +327,7 @@ public static Code orElse(Code code0, Code code1) {
};

/** @see BuiltIn#OP_DIV */
private static final Applicable OP_DIV =
new Applicable2<Integer, Integer, Integer>(BuiltIn.OP_DIV) {
@Override public Integer apply(Integer a0, Integer a1) {
return Math.floorDiv(a0, a1);
}
};
private static final Applicable OP_DIV = new IntDiv(BuiltIn.OP_DIV);

/** @see BuiltIn#GENERAL_OP_O */
private static final Applicable GENERAL_OP_O =
Expand Down Expand Up @@ -430,12 +425,7 @@ public static Code orElse(Code code0, Code code1) {
private static final List INT_MIN_INT = optionSome(Integer.MAX_VALUE);

/** @see BuiltIn#INT_DIV */
private static final Applicable INT_DIV =
new Applicable2<Integer, Integer, Integer>(BuiltIn.INT_DIV) {
@Override public Integer apply(Integer a0, Integer a1) {
return Math.floorMod(a0, a1);
}
};
private static final Applicable INT_DIV = new IntDiv(BuiltIn.INT_DIV);

/** @see BuiltIn#INT_MOD */
private static final Applicable INT_MOD = new IntMod(BuiltIn.INT_MOD);
Expand All @@ -452,23 +442,34 @@ private static class IntMod
}
}

/** Implements {@link #INT_DIV} and {@link #OP_DIV}. */
private static class IntDiv
extends Applicable2<Integer, Integer, Integer> {
IntDiv(BuiltIn builtIn) {
super(builtIn);
}

@Override public Integer apply(Integer a0, Integer a1) {
return Math.floorDiv(a0, a1);
}
}

/** @see BuiltIn#INT_PRECISION */
// 10^10 < 2^31 < 10^11
private static final List INT_PRECISION = optionSome(10);
private static final List INT_PRECISION = optionSome(32); // Java int 32 bits

/** @see BuiltIn#INT_QUOT */
private static final Applicable INT_QUOT =
new Applicable2<Integer, Integer, Integer>(BuiltIn.INT_QUOT) {
@Override public Integer apply(Integer a0, Integer a1) {
return Math.floorMod(a0, a1);
return a0 / a1;
}
};

/** @see BuiltIn#INT_REM */
private static final Applicable INT_REM =
new Applicable2<Integer, Integer, Integer>(BuiltIn.INT_REM) {
@Override public Integer apply(Integer a0, Integer a1) {
return Math.floorMod(a0, a1);
return a0 % a1;
}
};

Expand Down
65 changes: 51 additions & 14 deletions src/test/resources/script/builtIn.smli
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Int;
> val it =
> {abs=fn,compare=fn,div=fn,fromInt=fn,fromLarge=fn,fromString=fn,max=fn,
> maxInt=SOME 2147483647,min=fn,minInt=SOME 2147483647,mod=fn,
> precision=SOME 10,quot=fn,rem=fn,sameSign=fn,sign=fn,toInt=fn,toLarge=fn,
> precision=SOME 32,quot=fn,rem=fn,sameSign=fn,sign=fn,toInt=fn,toLarge=fn,
> toString=fn}
> : {abs:int -> int, compare:int * int -> order, div:int * int -> int,
> fromInt:int -> int, fromLarge:int -> int, fromString:string -> int option,
Expand Down Expand Up @@ -147,6 +147,15 @@ Sys.plan ();
> val it =
> "apply2(fnValue +, constant(2), apply2(fnValue *, constant(3), constant(4)))"
> : string
14 div 3;
> val it = 4 : int
14 div ~3;
> val it = ~5 : int

from (i, j) in [(14, 3), (~14, 3), (14, ~3), (~14, ~3)]
where (i div j) <> Int.`div` (i, j)
orelse (i mod j) <> Int.`mod` (i, j);
> val it = [] : {i:int, j:int} list

fn x => x + 1;
> val it = fn : int -> int
Expand Down Expand Up @@ -1467,6 +1476,18 @@ Int.compare;
> val it = fn : int * int -> order
Int.compare (4, 3);
> val it = GREATER : order
Int.`div`;
> val it = fn : int * int -> int
Int.`div` (14, 3);
> val it = 4 : int
Int.`div` (~14, 3);
> val it = ~5 : int
Int.`div` (14, ~3);
> val it = ~5 : int
Int.`div` (~14, ~3);
> val it = 4 : int
Int.`div` (0, ~3);
> val it = 0 : int
Int.fromInt;
> val it = fn : int -> int
Int.fromInt 3;
Expand All @@ -1491,26 +1512,42 @@ Int.min (4, 3);
> val it = 3 : int
Int.`mod`;
> val it = fn : int * int -> int
Int.`mod` (11, 3);
Int.`mod` (14, 3);
> val it = 2 : int
Int.`mod` (~11, 3);
Int.`mod` (~14, 3);
> val it = 1 : int
Int.`mod` (11, ~3);
Int.`mod` (14, ~3);
> val it = ~1 : int
Int.`mod` (~11, ~3);
Int.`mod` (~14, ~3);
> val it = ~2 : int
Int.`mod` (0, ~3);
> val it = 0 : int
Int.quot;
> val it = fn : int * int -> int
Int.quot (14, 3);
> val it = 4 : int
Int.quot (~14, 3);
> val it = ~4 : int
Int.quot (14, ~3);
> val it = ~4 : int
Int.quot (~14, ~3);
> val it = 4 : int
Int.quot (0, ~3);
> val it = 0 : int
Int.precision;
> val it = SOME 10 : int option
> val it = SOME 32 : int option
Int.rem;
> val it = fn : int * int -> int
Int.rem (11, 2);
> val it = 1 : int
Int.rem (~11, 2);
> val it = 1 : int
Int.rem (11, ~2);
> val it = ~1 : int
Int.rem (~11, ~2);
> val it = ~1 : int
Int.rem (14, 3);
> val it = 2 : int
Int.rem (~14, 3);
> val it = ~2 : int
Int.rem (14, ~3);
> val it = 2 : int
Int.rem (~14, ~3);
> val it = ~2 : int
Int.rem (0, ~3);
> val it = 0 : int
Int.sameSign;
> val it = fn : int * int -> bool
Int.sameSign (3, ~2);
Expand Down

0 comments on commit 7ee82dd

Please sign in to comment.