Skip to content

Commit 9903612

Browse files
committed
Make 'String.sub' more ergonomic
1 parent 6c4d926 commit 9903612

File tree

5 files changed

+40
-39
lines changed

5 files changed

+40
-39
lines changed

lib/Hash.trp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ let
1010
*)
1111
fun hashString s =
1212
(* String hash with fast paths for small strings *)
13-
let val len = strlen s
14-
val radix = 127
15-
fun charCodeAt i = String.subCode (s,i)
13+
let val len = String.size s
14+
val radix = 127
15+
val subCode = String.subCode s
1616
in case len of 0 => 0
17-
| 1 => charCodeAt 0
18-
| 2 => (radix * charCodeAt 0 + charCodeAt 1) andb Number.maxInt32
17+
| 1 => subCode 0
18+
| 2 => (radix * subCode 0 + subCode 1) andb Number.maxInt32
1919
| _ => let fun go idx acc =
2020
if len <= idx then acc
21-
else go (idx + 1) ((acc * radix + charCodeAt idx) andb Number.maxInt32)
21+
else go (idx + 1) ((acc * radix + subCode idx) andb Number.maxInt32)
2222
in go 0 0
2323
end
2424
end

lib/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ target of the *makefile*.
2727
## Design Principles
2828

2929
- File names are written in `CamelCase`. This makes them conform to the Standard ML Basis Library.
30-
- It is more important to match the function names and signatures in the Standard ML library than to
31-
improve on them. For example, `String.sub` would make more sense with the type `[Char] -> Int ->
32-
Char` but to match the SML library, we will stick with `[Char] * Int -> Char`.
30+
- While we will try to match function names in the Standard ML library, we may take the liberty to
31+
improve on the function signatures. For example, the function `String.sub` uses the same name as
32+
in SML but uses the signature `[Char] -> Int -> Char` rather than `[Char] * Int -> Char`.
3333
- Each module exports a single *record* with the same name as the file. This (1) makes it closer to
3434
the SML module system and (2) allows for name resolution, e.g. `HashMap.findOpt` and
3535
`ListPair.findOpt` can be used in the same file.

lib/String.trp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
(* TODO: Make strings merely lists of characters, similar to Haskell? Then a lot of things can be
2-
* moved out of the TCB? *)
31
import Number
42
import List
53

6-
let (** The maximum length of a string.
4+
(* TODO: Make strings merely lists of characters, similar to Haskell and SML? Then a lot of things
5+
* can be moved out of the TCB. *)
6+
7+
let val __substring = substring
8+
9+
(** The maximum length of a string.
710
*
811
* ECMA-262: 6.1.4 The String Type
912
*
@@ -19,15 +22,15 @@ let (** The maximum length of a string.
1922

2023
(** Returns the `i`th character of `s`, counting from zero. If `i` is out of bounds, then "" is
2124
* returned. *)
22-
fun sub (s,i) = substring (s, i, i+1)
25+
fun sub s i = __substring (s, i, i+1)
2326

2427
(** The character value at the given index. If `i` is out of bounds, then 0 (NULL) is
2528
* returned. *)
2629
(* TODO (#59): Rename to `sub'` when `'` symbols are properly supported. *)
27-
fun subCode (s,i) = charCodeAtWithDefault (s, i, 0)
30+
fun subCode s i = charCodeAtWithDefault (s, i, 0)
2831

2932
(** Returns the substring of `s`. Indices beyond the end of string are silently truncated. *)
30-
val substring = substring
33+
fun substring s i j = __substring (s, i, j)
3134

3235
(** The concatenation of all strings in `xs`. *)
3336
fun concat xs = let fun f ("",x') = x'
@@ -55,7 +58,7 @@ let (** The maximum length of a string.
5558

5659
(** Returns the list of characters in the string `s`. *)
5760
fun explode s = let fun go 0 acc = acc
58-
| go i acc = go (i-1) ((sub (s,i-1))::acc)
61+
| go i acc = go (i-1) ((sub s (i-1))::acc)
5962
in go (size s) [] end
6063

6164
(** Applies `f` to each element of `f` from left to right, returning the resulting string. *)

tests/lib/String.trp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,32 @@ let val tests = Unit.group "String" [
1111
],
1212
let val s = "Hello"
1313
in Unit.group "sub" [
14-
Unit.it "is 'H' for 0" (Unit.isEq "H" (String.sub (s, 0)))
15-
, Unit.it "is 'e' for 1" (Unit.isEq "e" (String.sub (s, 1)))
16-
, Unit.it "is 'l' for 2" (Unit.isEq "l" (String.sub (s, 2)))
17-
, Unit.it "is 'l' for 3" (Unit.isEq "l" (String.sub (s, 3)))
18-
, Unit.it "is 'o' for 4" (Unit.isEq "o" (String.sub (s, 4)))
19-
, Unit.it "is '' for 5" (Unit.isEq "" (String.sub (s, 5)))
20-
, Unit.it "is '' for 6" (Unit.isEq "" (String.sub (s, 6)))
14+
Unit.it "is 'H' for 0" (Unit.isEq "H" (String.sub s 0))
15+
, Unit.it "is 'e' for 1" (Unit.isEq "e" (String.sub s 1))
16+
, Unit.it "is 'l' for 2" (Unit.isEq "l" (String.sub s 2))
17+
, Unit.it "is 'l' for 3" (Unit.isEq "l" (String.sub s 3))
18+
, Unit.it "is 'o' for 4" (Unit.isEq "o" (String.sub s 4))
19+
, Unit.it "is '' for 5" (Unit.isEq "" (String.sub s 5))
20+
, Unit.it "is '' for 6" (Unit.isEq "" (String.sub s 6))
2121
]
2222
end,
2323
let val s = "World!"
2424
in Unit.group "subCode" [
25-
Unit.it "is 87 for 0" (Unit.isEq 87 (String.subCode (s,0)))
26-
, Unit.it "is 111 for 1" (Unit.isEq 111 (String.subCode (s,1)))
27-
, Unit.it "is 114 for 2" (Unit.isEq 114 (String.subCode (s,2)))
28-
, Unit.it "is 108 for 3" (Unit.isEq 108 (String.subCode (s,3)))
29-
, Unit.it "is 100 for 4" (Unit.isEq 100 (String.subCode (s,4)))
30-
, Unit.it "is 33 for 5" (Unit.isEq 33 (String.subCode (s,5)))
31-
, Unit.it "is 0 for 6" (Unit.isEq 0 (String.subCode (s,6)))
25+
Unit.it "is 87 for 0" (Unit.isEq 87 (String.subCode s 0))
26+
, Unit.it "is 111 for 1" (Unit.isEq 111 (String.subCode s 1))
27+
, Unit.it "is 114 for 2" (Unit.isEq 114 (String.subCode s 2))
28+
, Unit.it "is 108 for 3" (Unit.isEq 108 (String.subCode s 3))
29+
, Unit.it "is 100 for 4" (Unit.isEq 100 (String.subCode s 4))
30+
, Unit.it "is 33 for 5" (Unit.isEq 33 (String.subCode s 5))
31+
, Unit.it "is 0 for 6" (Unit.isEq 0 (String.subCode s 6))
3232
]
3333
end,
3434
let val s = "Hello Troupe!"
3535
in Unit.group "substring" [
36-
Unit.it "is 'Hello' for 0 5" (Unit.isEq "Hello" (String.substring (s, 0, 5)))
37-
, Unit.it "is 'Troupe' for 6 12" (Unit.isEq "Troupe" (String.substring (s, 6, 12)))
38-
, Unit.it "is 'Troupe!' for 6 13" (Unit.isEq "Troupe!" (String.substring (s, 6, 13)))
39-
, Unit.it "is 'Troupe!' for 6 14" (Unit.isEq "Troupe!" (String.substring (s, 6, 13)))
36+
Unit.it "is 'Hello' for 0 5" (Unit.isEq "Hello" (String.substring s 0 5))
37+
, Unit.it "is 'Troupe' for 6 12" (Unit.isEq "Troupe" (String.substring s 6 12))
38+
, Unit.it "is 'Troupe!' for 6 13" (Unit.isEq "Troupe!" (String.substring s 6 13))
39+
, Unit.it "is 'Troupe!' for 6 14" (Unit.isEq "Troupe!" (String.substring s 6 14))
4040
]
4141
end,
4242
Unit.group "concat" [
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
import String
2-
3-
let val x = String.sub ("hello", 0)
1+
let val x = substring ("hello", 0, 1)
42
val y = "1" ^ "2"
53
val s = ("Hello" raisedTo `{alice}`) ^ ", " ^ ("World" raisedTo `{bob}`)
64
val i = 3 raisedTo `{charlie}`
75
val j = 5 raisedTo `{dorothy}`
8-
in (x,y,s, substring (s, i, j))
9-
end
6+
in (x, y, s, substring (s, i, j))
7+
end

0 commit comments

Comments
 (0)