FOR ALL
FOR ALL introduces type variables in a type, so that an ASSUME can declare a value or function that works for any type.
Syntax
FOR ALL a
FOR ALL a AND b
FOR ALL a AND b AND c
FOR ALL comes first in the type, followed by the type that uses the variables.
Example file:
-- FOR ALL Examples
-- Universal quantifier for polymorphic type signatures
--------------------------------------------------------------------------------
-- Basic Polymorphic Type Declarations
--------------------------------------------------------------------------------
-- Identity function: works for any type
ASSUME identity IS
FOR ALL a
A FUNCTION FROM a TO a
-- Constant function: ignores second argument
ASSUME const IS
FOR ALL a AND b
A FUNCTION FROM a AND b TO a
--------------------------------------------------------------------------------
-- List Operations (Polymorphic)
--------------------------------------------------------------------------------
-- Map: apply function to each element
ASSUME map IS
FOR ALL a AND b
A FUNCTION
FROM FUNCTION FROM a TO b
AND LIST OF a
TO LIST OF b
-- Filter: keep elements matching predicate
ASSUME filter IS
FOR ALL a
A FUNCTION
FROM FUNCTION FROM a TO BOOLEAN
AND LIST OF a
TO LIST OF a
-- Fold: reduce list to single value
ASSUME foldl IS
FOR ALL a AND b
A FUNCTION
FROM FUNCTION FROM b AND a TO b
AND b
AND LIST OF a
TO b
--------------------------------------------------------------------------------
-- Custom Algebraic Types with Type Parameters
--------------------------------------------------------------------------------
-- A choice between two types (like Either in Haskell)
DECLARE Choice OF a, b
IS ONE OF
Left HAS payload IS AN a
Right HAS payload IS A b
-- Optional value (like Maybe in Haskell)
DECLARE Optional OF a
IS ONE OF
None
Some HAS value IS AN a
-- A pair of two values
DECLARE Pair OF a, b
HAS first IS AN a
second IS A b
--------------------------------------------------------------------------------
-- Functions Using Custom Types
--------------------------------------------------------------------------------
-- Handle either alternative of a Choice
ASSUME either IS
FOR ALL a AND b AND c
A FUNCTION
FROM FUNCTION FROM a TO c
AND FUNCTION FROM b TO c
AND Choice OF a, b
TO c
-- Extract value from Optional with default
ASSUME fromOptional IS
FOR ALL a
A FUNCTION
FROM a
AND Optional OF a
TO a
-- Create a pair
ASSUME makePair IS
FOR ALL a AND b
A FUNCTION FROM a AND b TO Pair OF a, b
--------------------------------------------------------------------------------
-- Implementing Polymorphic Functions with GIVEN
--------------------------------------------------------------------------------
-- The definition style uses GIVEN ... IS A TYPE
GIVEN a IS A TYPE
b IS A TYPE
f IS A FUNCTION FROM a TO b
list IS A LIST OF a
GIVETH A LIST OF b
myMap f list MEANS
CONSIDER list
WHEN EMPTY THEN EMPTY
WHEN x FOLLOWED BY xs THEN f x FOLLOWED BY myMap f xs
-- Length works for any list type
GIVEN a IS A TYPE
list IS A LIST OF a
GIVETH A NUMBER
myLength list MEANS
CONSIDER list
WHEN EMPTY THEN 0
WHEN x FOLLOWED BY xs THEN 1 PLUS myLength xs
-- Reverse a list (simplified - just demonstrates the pattern)
GIVEN a IS A TYPE
list IS A LIST OF a
GIVETH A LIST OF a
myReverse list MEANS
CONSIDER list
WHEN EMPTY THEN EMPTY
WHEN x FOLLOWED BY xs THEN append (myReverse xs) (x FOLLOWED BY EMPTY)
-- Helper for append
GIVEN a IS A TYPE
list1 IS A LIST OF a
list2 IS A LIST OF a
GIVETH A LIST OF a
append list1 list2 MEANS
CONSIDER list1
WHEN EMPTY THEN list2
WHEN x FOLLOWED BY xs THEN x FOLLOWED BY append xs list2
--------------------------------------------------------------------------------
-- Using Polymorphic Functions
--------------------------------------------------------------------------------
-- Test data
DECIDE numbers IS LIST 1, 2, 3, 4, 5
DECIDE strings IS LIST "a", "b", "c"
-- Apply myLength to different list types
#EVAL myLength numbers -- 5
#EVAL myLength strings -- 3
-- Map with different types
GIVEN n IS A NUMBER
double n MEANS n TIMES 2
#EVAL myMap double numbers -- LIST 2, 4, 6, 8, 10
--------------------------------------------------------------------------------
-- Higher-Order Polymorphic Functions
--------------------------------------------------------------------------------
-- Function composition
ASSUME compose IS
FOR ALL a AND b AND c
A FUNCTION
FROM FUNCTION FROM b TO c
AND FUNCTION FROM a TO b
TO FUNCTION FROM a TO c
-- Flip argument order
ASSUME flip IS
FOR ALL a AND b AND c
A FUNCTION
FROM FUNCTION FROM a AND b TO c
TO FUNCTION FROM b AND a TO c
--------------------------------------------------------------------------------
-- Polymorphic Tree Type
--------------------------------------------------------------------------------
DECLARE Tree OF a
IS ONE OF
Leaf HAS value IS AN a
Node HAS
left IS A Tree OF a
right IS A Tree OF a
-- Count nodes in a tree
GIVEN a IS A TYPE
tree IS A Tree OF a
GIVETH A NUMBER
treeSize tree MEANS
CONSIDER tree
WHEN Leaf v THEN 1
WHEN Node l r THEN treeSize l PLUS treeSize r
-- Example tree
DECIDE exampleTree IS
Node WITH
left IS Leaf WITH value IS 1
right IS Node WITH
left IS Leaf WITH value IS 2
right IS Leaf WITH value IS 3
#EVAL treeSize exampleTree -- 3
Examples
One type variable
ASSUME identity IS
FOR ALL a
A FUNCTION FROM a TO a
identity takes a value of any type and returns a value of the same type.
Several type variables
ASSUME map IS
FOR ALL a AND b
A FUNCTION
FROM FUNCTION FROM a TO b
AND LIST OF a
TO LIST OF b
For all types a and b, map takes a function from a to b and a list of a, and returns a list of b.
With a parameterised type
DECLARE Choice OF a, b
IS ONE OF
Left HAS payload IS AN a
Right HAS payload IS A b
ASSUME choose IS
FOR ALL a AND b AND c
A FUNCTION
FROM FUNCTION FROM a TO c
AND FUNCTION FROM b TO c
AND Choice OF a, b
TO c
FOR ALL and GIVEN
FOR ALL declares a polymorphic type with no definition, in an ASSUME.
A function that is defined gets its type variables from GIVEN … IS A TYPE instead:
GIVEN a IS A TYPE
b IS A TYPE
f IS A FUNCTION FROM a TO b
list IS A LIST OF a
GIVETH A LIST OF b
`apply to each` f list MEANS
CONSIDER list
WHEN EMPTY THEN EMPTY
WHEN x FOLLOWED BY xs THEN f x FOLLOWED BY `apply to each` f xs
Both give the function the same type.
Type variables
- They are usually single lowercase letters (
a,b,c), but any identifier works. - They are in scope only in the type that follows.
- The names in one
FOR ALLmust be distinct:FOR ALL a AND ais an error.
Not a quantifier over lists
FOR ALL works on types, not on values. To test every element of a list, or some element, use all or any from the prelude with a YIELD function:
IMPORT prelude
GIVEN amounts IS A LIST OF NUMBER
GIVETH A BOOLEAN
`every amount is positive` amounts MEANS all (GIVEN x YIELD x > 0) amounts
In other languages
| L4 | Haskell | TypeScript | Java |
|---|---|---|---|
FOR ALL a |
forall a. |
<T> |
<T> |
FOR ALL a AND b |
forall a b. |
<T, U> |
<T, U> |
Related pages
- GIVEN and GIVETH: type parameters of a defined function
- ASSUME: declare a name without a definition
- DECLARE: Type expressions:
FUNCTION FROM … TO …andTYPE - prelude: polymorphic standard functions