Skip to content

Commit

Permalink
Require types to start with an uppercase letter (#1583)
Browse files Browse the repository at this point in the history
Closes #1547 , which was caused by misspelled/nonexistent types being interpreted as type variables.  In #1550 I proposed one solution to the problem, namely, to stop implicitly quantifying types and require explicit `forall` on any polymorphic type.  This PR represents an alternative solution: to keep implicit quantification but require all types to start with an uppercase letter, as in Haskell.  I think I like this one better but I'm open to feedback.

Specifically, with this PR:
- All built-in type constructors (`Int`, `Cmd`, `Unit`, etc.) must start with a capital letter
- Type variables:
    - Must start with a lowercase letter or underscore
    - May not be named a lowercase version of a type constructor, *e.g.* `int`
        - This is important so that old code with lowercase types is not silently accepted by parsing the former types as implicitly quantified type variables; even in cases where old code no longer typechecks, this will give better error messages.
- Term variables:
    - May start with upper- or lowercase
    - May be named lowercase versions of type names, *e.g.* `let f : Int -> Int = \int. int + 1` is fine

This PR obviously represents a bigger breaking change.  Once we merge this we might consider adding an option to `swarm format` to be able to parse old code with lowercase types and then reformat it with uppercase, to aid in porting code.

Once this is merged I will also regenerate the wiki pages that mention types.

Closes #1550.
  • Loading branch information
byorgey authored May 21, 2024
1 parent ff349d8 commit 1a4dcd8
Show file tree
Hide file tree
Showing 56 changed files with 540 additions and 465 deletions.
90 changes: 45 additions & 45 deletions data/entities.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@
- |
An equipped `linotype`{=entity} device enables the `format` command:
```
format : a -> text
format : a -> Text
```
which can turn any value into a suitable text representation.
properties: [pickable]
Expand All @@ -353,8 +353,8 @@
- |
Facilitates the concatenation of text values.
- |
The infix operator `++ : text -> text -> text`{=snippet}
can be used to concatenate two text values. For example,
The infix operator `++ : Text -> Text -> Text`{=snippet}
can be used to concatenate two `Text`{=type} values. For example,
- |
```
let numWidgets = 42
Expand All @@ -370,9 +370,9 @@
- Simple, yet accurate measuring device. Can determine the length of a text value.
- |
```
chars : text -> int
chars : Text -> Int
```
computes the number of characters in a `text`{=type} value.
computes the number of characters in a `Text`{=type} value.
properties: [pickable]
capabilities: [charcount]
- name: wedge
Expand All @@ -384,9 +384,9 @@
- |
An equipped `wedge`{=entity} enables the `split` command:
```
split : int -> text -> text * text
split : Int -> Text -> Text * Text
```
splits a `text`{=type} value into two pieces, one before the given index and one after.
splits a `Text`{=type} value into two pieces, one before the given index and one after.
properties: [pickable]
capabilities: [split]
- name: string
Expand All @@ -397,23 +397,23 @@
- A long, flexible device for transferring either force or information, made of twisted cotton fibers. Multiple strings can also be woven into larger configurations such as cloth or nets.
- |
An equipped `string`{=entity} device enables several commands for working with
`text`{=type} values:
`Text`{=type} values:
- |
`format : a -> text` can turn any value into a suitable text
`format : a -> Text` can turn any value into a suitable text
representation.
- |
The infix operator `++ : text -> text -> text`{=snippet}
The infix operator `++ : Text -> Text -> Text`{=snippet}
can be used to concatenate two text values. For example,
- |
```
let numWidgets = 42
in "Number of widgets: " ++ format numWidgets
```
- |
`chars : text -> int` computes the number of characters in a
`text`{=type} value.
`chars : Text -> Int` computes the number of characters in a
`Text`{=type} value.
- |
`split : int -> text -> text * text` splits a `text`{=type} value into
`split : Int -> Text -> Text * Text` splits a `Text`{=type} value into
two pieces, one before the given index and one after.
properties: [pickable]
capabilities: [format, concat, charcount, split]
Expand All @@ -427,10 +427,10 @@
back, shaped for some reason into a ring. When equipped, it
enables two functions:
- |
`charAt : int -> text -> int` returns the numeric code of the
character at a specific index in a (0-indexed) `text`{=type} value.
`charAt : Int -> Text -> Int` returns the numeric code of the
character at a specific index in a (0-indexed) `Text`{=type} value.
- |
`toChar : int -> text` creates a singleton (length-1) `text`{=type}
`toChar : Int -> Text` creates a singleton (length-1) `Text`{=type}
value containing a character with the given numeric code.
properties: [pickable]
capabilities: [code]
Expand All @@ -443,7 +443,7 @@
- Lambdas can also be used to create functions. For example,
- |
```
def thrice : cmd unit -> cmd unit = \c. c;c;c end
def thrice : Cmd Unit -> Cmd Unit = \c. c;c;c end
```
- defines the function `thrice`{=snippet} which repeats a command three times.
properties: [pickable, growable]
Expand Down Expand Up @@ -575,10 +575,10 @@
description:
- This enables the `structure` and `floorplan` commands to locate and analyze structures placed in the world.
- |
`structure : text -> int -> cmd (unit + (int * (int * int)))`
`structure : Text -> Int -> Cmd (Unit + (Int * (Int * Int)))`
- Gets the x, y coordinates of the southwest corner of a constructed structure, by name and index.
- |
`floorplan : text -> cmd (int * int)`
`floorplan : Text -> Cmd (Int * Int)`
- Gets the dimensions of a structure template.
properties: [pickable]
capabilities: [structure]
Expand Down Expand Up @@ -753,7 +753,7 @@
description:
- A broad, sturdy surface that can be attached to a robot and used to `push` objects.
- |
`push : cmd unit` will advance the robot and the entity in front of it forward by one step.
`push : Cmd Unit` will advance the robot and the entity in front of it forward by one step.
properties: [pickable]
capabilities: [push]
- name: grabber
Expand All @@ -764,7 +764,7 @@
- A grabber arm is an all-purpose, hydraulically controlled device that can manipulate other items and robots via the `grab`, `place`, and `give` commands.
- The `grab` command takes no arguments; it simply grabs whatever is available, and also returns the name of the grabbed thing as a string. It raises an exception if run in a cell that does not contain an item.
- The `place` command takes one argument, the name of the item to place. The item is removed from the robot's inventory and placed in the robot's current cell (which must be empty). Raises an exception if the operation fails.
- "The `give` command takes two arguments: the actor to give an item to (which can be at most 1 cell away), and the name of the item to give. Raises an exception if the operation fails."
- "The `give` command takes two arguments: the `Actor`{=type} to give an item to (which can be at most 1 cell away), and the name of the item to give. Raises an exception if the operation fails."
capabilities: [grab, give, place]
properties: [pickable]
- name: fast grabber
Expand Down Expand Up @@ -888,11 +888,11 @@
expression or command locally within another expression.
- |
```
def m2 : cmd unit = move; move end
def m2 : Cmd Unit = move; move end
```
- |
```
let x : int = 3 in x^2 + 2*x + 1
let x : Int = 3 in x^2 + 2*x + 1
```
- The type annotations in `def`{=snippet} are optional.
properties: [pickable]
Expand Down Expand Up @@ -936,7 +936,7 @@
char: '$'
description:
- "With a scanner device, robots can use the `scan` command to learn about their surroundings. Simply give `scan` a direction in which to scan, and information about the scanned item (if any) will be added to the robot's inventory."
- "A scanner also enables `blocked : cmd bool`, which returns a boolean value indicating whether the robot's path is blocked (i.e. whether executing a `move` command would fail); `ishere : text -> cmd bool` for checking whether the current cell contains a particular entity; and `isempty : cmd bool` for checking whether the current cell is empty of entities. Note that `ishere` and `isempty` do not detect robots, only entities."
- "A scanner also enables `blocked : Cmd Bool`, which returns a boolean value indicating whether the robot's path is blocked (i.e. whether executing a `move` command would fail); `ishere : Text -> Cmd Bool` for checking whether the current cell contains a particular entity; and `isempty : Cmd Bool` for checking whether the current cell is empty of entities. Note that `ishere` and `isempty` do not detect robots, only entities."
- "Finally, robots can use the `upload` command to copy their accumulated knowledge to another nearby robot; for example, `upload base`."
properties: [pickable]
capabilities: [scan, sensefront, sensehere]
Expand All @@ -946,7 +946,7 @@
description:
- An electronic "nose" that can tell how far away something is.
- |
`sniff : text -> cmd int` returns the distance to the nearest specified entity.
`sniff : Text -> Cmd Int` returns the distance to the nearest specified entity.
properties: [pickable]
capabilities: [detectdistance]
- name: flash memory
Expand Down Expand Up @@ -998,10 +998,10 @@
char: 'C'
description:
- |
A counter enables the command `count : text -> cmd int`,
A counter enables the command `count : Text -> Cmd Int`,
which counts how many occurrences of an entity are currently
in the inventory. This is an upgraded version of the `has`
command, which returns a bool instead of an int and does
command, which returns a `Bool`{=type} instead of an `Int`{=type} and does
not require any special device.
properties: [pickable]
capabilities: [count]
Expand All @@ -1024,20 +1024,20 @@
addition to the usual arithmetic on numbers, an ADT calculator can
also do arithmetic on types! After all, the helpful typewritten manual
explains, a type is just a collection of values, and a finite collection
of values is just a fancy number. For example, the type `bool`{=type} is
of values is just a fancy number. For example, the type `Bool`{=type} is
just a fancy version of the number 2, where the two things happen to be
labelled `false` and `true`. There are also types `unit`{=type} and
labelled `false` and `true`. There are also types `Unit`{=type} and
`void`{=type} that correspond to 1 and 0, respectively.
- |
The product of two types is a type of pairs, since, for example,
if `t`{=type} is a type with three elements, then there are 2 * 3 = 6
different pairs containing a `bool`{=type} and a `t`{=type}, that is, 6 elements
of type `bool * t`{=type}. For working with products of types, the ADT
different pairs containing a `Bool`{=type} and a `t`{=type}, that is, 6 elements
of type `Bool * t`{=type}. For working with products of types, the ADT
calculator enables pair syntax `(1, "Hi!")` as well as the projection
functions `fst : a * b -> a` and `snd : a * b -> b`.
- |
The sum of two types is a type with two options; for example, a
value of type `bool + t`{=type} is either a `bool`{=type} value or a `t`{=type} value,
value of type `Bool + t`{=type} is either a `Bool`{=type} value or a `t`{=type} value,
and there are `2 + 3 == 5` such values. For working with sums of
types, the ADT calculator provides the injection functions `inl :
a -> a + b` and `inr : b -> a + b`, as well as the case analysis
Expand All @@ -1057,7 +1057,7 @@
- |
`turn west; move; turn north`
- |
It also enables the `heading : cmd dir` command, which returns the
It also enables the `heading : Cmd Dir` command, which returns the
robot's current heading. For example, the following code moves
east and then restores the same heading as before:
- |
Expand All @@ -1071,9 +1071,9 @@
description:
- A clock is a device for keeping track of time. It enables the `wait` and `time` commands.
- |
`time : cmd int` returns the current time, measured in game ticks since the beginning of the game.
`time : Cmd Int` returns the current time, measured in game ticks since the beginning of the game.
- |
`wait : int -> cmd unit` causes a robot to sleep for a specified amount of time (measured in game ticks).
`wait : Int -> Cmd Unit` causes a robot to sleep for a specified amount of time (measured in game ticks).
properties: [pickable]
capabilities: [timeabs, timerel]
- name: hourglass
Expand All @@ -1083,7 +1083,7 @@
description:
- An hourglass can measure the relative passage of time. It enables the `wait` command.
- |
`wait : int -> cmd unit` causes a robot to sleep for a specified amount of time (measured in game ticks).
`wait : Int -> Cmd Unit` causes a robot to sleep for a specified amount of time (measured in game ticks).
properties: [pickable]
capabilities: [timerel]
- name: rolex
Expand All @@ -1093,7 +1093,7 @@
description:
- Enables robots to use the `watch` and `wait` commands.
- |
`watch : dir -> cmd unit` will mark an adjacent (in the specified direction) location of interest to monitor for placement or removal of items.
`watch : Dir -> Cmd Unit` will mark an adjacent (in the specified direction) location of interest to monitor for placement or removal of items.
A subsequent call to `wait` will be interrupted upon a change to the location.
properties: [pickable]
capabilities: [timerel, wakeself]
Expand Down Expand Up @@ -1156,12 +1156,12 @@
waves off them and listening for the echo. This capability can be
accessed via two commands:
- |
`meet : cmd (unit + actor)` tries to locate a
`meet : Cmd (Unit + Actor)` tries to locate a
nearby actor (a robot, or... something else?) up to one cell away.
It returns a reference to the nearest actor, or a unit value if
none are found.
- |
`meetAll : (b -> actor -> cmd b) -> b -> cmd b` runs a command on
`meetAll : (b -> Actor -> Cmd b) -> b -> Cmd b` runs a command on
every nearby actor (other than oneself), folding over the results
to compute a final result of type `b`{=type}. For example, if
`x`{=snippet}, `y`{=snippet}, and `z`{=snippet}
Expand All @@ -1177,7 +1177,7 @@
- |
A GPS receiver triangulates your current (x,y) coordinates from
some convenient satellite signals,
enabling the command `whereami : cmd (int * int)`.
enabling the command `whereami : Cmd (Int * Int)`.
properties: [pickable]
capabilities: [senseloc]
- name: tweezers
Expand Down Expand Up @@ -1205,7 +1205,7 @@
- |
Also allows manipulating composite values consisting of a
collection of named fields. For example, `[x = 2, y = "hi"]`
is a value of type `[x : int, y : text]`{=type}. Individual fields
is a value of type `[x : Int, y : Text]`{=type}. Individual fields
can be projected using dot notation. For example,
`let r = [y="hi", x=2] in r.x` has the value `2`. The order
of the fields does not matter.
Expand Down Expand Up @@ -1234,11 +1234,11 @@
description:
- A small device with multiple keys, adapted for your unique anatomy.
- |
`installKeyHandler : text -> (key -> cmd unit) -> cmd unit`
`installKeyHandler : Text -> (Key -> Cmd Unit) -> Cmd Unit`
installs a custom handler function that can be activated to
respond to keyboard inputs typed at the REPL.
- |
`key : text -> key` constructs values of type `key`{=type}, for
`key : Text -> Key` constructs values of type `Key`{=type}, for
example `key "Down"` or `key "C-S-x"`.
properties: [pickable]
capabilities: [handleinput]
Expand All @@ -1249,7 +1249,7 @@
description:
- A device to solve the halting problem. When asked if a particular robot program will halt, it always answers YES. And it is always correct... or else!
- |
Enables the command `halt : actor -> cmd unit` which takes
Enables the command `halt : Actor -> Cmd Unit` which takes
a robot as an argument and, if it is up to one cell away,
cancels its currently running program (if any). In creative mode,
there is no distance limitation.
Expand All @@ -1269,7 +1269,7 @@
description:
- |
Enables the `teleport` command, which takes as arguments an
`actor`{=type} and a location in the form of a pair of
`Actor`{=type} and a location in the form of a pair of
coordinates, and teleports the given actor to the specified
coordinates (and may also have some improbable side effects).
properties: [pickable]
Expand Down
2 changes: 1 addition & 1 deletion data/scenarios/Challenges/2048.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ objectives:
as base {has "2048"}
} { return false }
solution: |
def makeN : int -> cmd unit = \n.
def makeN : Int -> Cmd Unit = \n.
if (n == 1)
{harvest; return ()}
{makeN (n/2); makeN (n/2); make (format n)}
Expand Down
2 changes: 1 addition & 1 deletion data/scenarios/Challenges/Ranching/_beekeeping/queenbee.sw
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Spawns worker bees when structures are detected

def doN = \n. \f. if (n > 0) {f; doN (n - 1) f} {}; end;
def mod : int -> int -> int = \a. \b. a - (a/b)*b end;
def mod : Int -> Int -> Int = \a. \b. a - (a/b)*b end;
def abs = \n. if (n < 0) {-n} {n} end;
def min = \x. \y. if (x < y) {x} {y} end;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def collectWool =

turn back;

let forever : cmd unit -> cmd unit = \c. c ; forever c in
let forever : Cmd Unit -> Cmd Unit = \c. c ; forever c in
forever sweepAreaForWool;
end;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def turnCloverDirection =

def decideDirection =

let randdir : cmd dir =
let randdir : Cmd Dir =
d <- random 4;
return $ if (d == 0) {
north
Expand All @@ -62,8 +62,8 @@ def decideDirection =
}
end;

let forever : cmd unit -> cmd unit = \c. c ; forever c in
let repeat : int -> cmd unit -> cmd unit =
let forever : Cmd Unit -> Cmd Unit = \c. c ; forever c in
let repeat : Int -> Cmd Unit -> Cmd Unit =
\n. \c. if (n == 0) {} {c ; repeat (n-1) c} in


Expand Down
4 changes: 2 additions & 2 deletions data/scenarios/Challenges/Ranching/_powerset/setup.sw
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ def elif = \t. \then. \else. {if t then else} end
def else = \t. t end

// modulus function (%)
def mod : int -> int -> int = \i. \m.
def mod : Int -> Int -> Int = \i. \m.
i - m * (i / m)
end

Expand Down Expand Up @@ -218,7 +218,7 @@ def setup = \inputCardinality.
/**
One-based ordinal of the item.
*/
def getOrdinal : text -> cmd int = \item.
def getOrdinal : Text -> Cmd Int = \item.
count item;
end;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def computeTriangularNumber = \n.
(n * (n + 1)) / 2
end;

def mod : int -> int -> int = \i.\m.
def mod : Int -> Int -> Int = \i.\m.
i - m * (i / m);
end

Expand Down Expand Up @@ -46,7 +46,7 @@ def teleportToDetectResult = \referenceLoc. \relativeLoc.
teleport self newLoc;
end;

def getOrdinal : text -> cmd int = \item.
def getOrdinal : Text -> Cmd Int = \item.
count $ item ++ "-ordinal";
end;

Expand Down Expand Up @@ -166,7 +166,7 @@ def handleMarker = \boardWidth. \boardHeight.
Precondition: Facing east at location (0, 0).
*/
def iterateAllTiles : cmd unit -> cmd unit = \func.
def iterateAllTiles : Cmd Unit -> Cmd Unit = \func.
let b = "border" in
isOnBottomBorder <- itemIsHere b;
if isOnBottomBorder {} {
Expand Down
Loading

0 comments on commit 1a4dcd8

Please sign in to comment.