Amber
Amber is an esoteric programming language that builds upon N-Type using ADT's. Its is only a superset, so any of the things already in N-Type, are preserved(though N-Type code wont be valid as Amber code). It was designed in such a way that Types and ATD's were interchangeable in all cases, and ofcourse, ATD's technically also are types, though they have noticeable differences. Amber adds a number of new features, making it, arguably, not an esolang(yet it still is such a strange language one probably would be dismissed when saying this)
Constructs, syntax, and computation
Lists
Lists are essential to Amber. They are made up of either cases, creators, or matches. These may hold any number of arbitraries in each object. A list is written as following:
[f, g, h,...]
this works as both data, and a function. When applied as a function f onto an input x, it chooses the leftmost function g that accepts an object of the same type as x, and then returns g(x). there is an implicit identity function at the end of the list(always at the end), which applies to an object of any type. as such, [] is an identity function(since the only function is the identity, at the end of the list, implicitly). As a type, this holds only itself. Every function must be a list. It can be locally referenced within itself as L, however only as a type.
Matches
in Amber, matches, originating in N-Type, are functions, written as <x -> y>. When acting as types, they simply hold themselves. As functions, they take an input, if it is of type x, return y. locally within themselves(this "Locality" is caused by <...>), they refer recursively to themselves only as T, and may only recurse on the left side of an arrow(any arrow, that is). So, <T -> ...> is legal, <... -> T -> ...> is legal, however <... -> T> is not. These are right associative(a -> b -> c = a -> (b -> c). In the case where the input isnt of that type, it's simply "rejected"(as opposed to accepting it).
Cases
Written as <x <- y z w ...>, this is a case. It takes one input of type y, one of z, ect.. This, instead of ignoring the inputted values, returns the object Ex<y z w ...>, where the type names are substituted for the values that was inputted.
Objects
Amber objects are functions, but also atoms. They dont really mean anything. But when an object [Ex<y z ...>] is applied as functions on
f, it returns [Ex<f(y) f(z) f(...)>]. As such [Ex<>] is an atom. [Ex<>](f) = [Ex<f>]
Creators
<x.y> is a creator. When applying as a function, any reference to x in the body of y. These refer recursively within themselves as C. As well as matches these may only recurse on the left of an arrow.
Types
For some object x, its type is made up of all value x(y), where y is any value of the type x accepts. If we say x was arity 2, it would also include x(y,z), and such for all rarities, going up only to the arity of the function. There are a few builtin's for changing types, or creating them, as well as some builtin types. -x is a type that holds only x. W(x,y) is the type x, without any of the objects in y. Px is the type of all input accepted into function x. All of these preserve their functional identities, bur recursion of the whole list as a type uses these new types, not the old ones. Also, D(x,y) uses the function x, but the type of y.
Other
Assignment
Assignment is written as:
x : y
Exactly like in N-Type. These may not recurse.
Application
Application of an arity n function f is written as f(x1,x2,x3,...,xn).
=, \, ', 1, & :x
<f = g> is a function. It takes a single input x. If g(x) ≠ x return g(x) else f(x). f(:x) = x(always). And, if x = [y,z,w,...], then '(x) = [z,w,...,y](left rotation). Note that a lists type holds the results for any of the rotations using '. 1([x, y, z, ...]) = [x]. Last, \([Ex<y z ...>]) = [y,z,...].
Comments
A line can be commented out as follows:
#Everything after this # on this line is a comment
Builtins
These are the builtins:
i : [[E0<>],<+ <- L>] #ADT style natural numbers l : [<x.<x -> x>>] #N-type stuff from here on out N : [<x.<M -> l(x)>>] v : [D([],<L -> L>)] M : [-[<v -> L>]]
Examples
K:
K : [<x.<v -> x>>]
KI:
ʞ : [K([])]
I:
I : []
Set of objects:
O : [P\]
the type made up of the objects in x & y, with a function f:
+ : D([P[<x -> v>, <y -> v>]],f)
as a Creator, taking input in the same order:
+ : <x.<y.<f.D([P[<x -> v>, <y -> v>]],f)>>>
Computational class
Amber is (trivially) Turing complete, via compilation from Lambda calculus:
{\x.e} --> [<x.{e}>]
{x y} --> {x}({y})
however, it may be interesting to know what computational class it is in the case where every creator must have its body be a composition of matches, and when these matches may not have creators within themselves(N-type rules).