Get the code: learnbqn.bqn
BQN is a modern array language (similar to APL) that aims to eliminate burdensome aspects of the APL tradition.
It is recommended to try these code examples out in a REPL. The online REPL is recommended for quick start, since it comes with keyboard and easy to access help. You can try building CBQN for a local install, but it will need keyboard setup.
# This is a comment.
# The characters ',' and `β` are statement separators.
##################
# Main datatypes #
##################
# Numbers
1,2,3,4
Β―1,Β―2,Β―3 # Negative numbers are written with a high minus
Ο,β,Β―Ο,Β―β # Pi and Infinity are defined constants
1_234_456 # You can add underscores in between numbers
# This does not change their value
1.3E4 # Scientific notation is supported
# Characters
'a','β₯'
'
' # Yes, you can put *any* character in a character literal
@ # Null character ('\0' in C)
# Arrays
1βΏ2βΏ3 # Stranding, good for simple lists
β¨1,2,3β© # General list notation
β¨1βΏ2,2βΏ3β© # Both can be mixed
[1βΏ2,2βΏ3] # Array notation
# An array is multidimensional, as opposed to containing sublists.
# It must be rectangular in shape (a grid structure rather than a tree structure)
[1βΏ2βΏ3,4βΏ5] # This is hence invalid
# May be familiar coming from Numpy, MATLAB and similar languages.
"asdf" # Character array (String)
"newline
separated" # Allows newlines
"quo""tes" # Escape a double quote by typing it twice
# Functions
1{π¨+π©}3 # All functions are infix
# π¨ is left argument, π© is right argument
{-π©}5 # π¨ can be omitted
1+3 # Same as the above
{ππ©} # π is a recursive call
# (this function will loop forever)
{π¨ π π©: π¨+π©} # Functions can have headers (too many cases to discuss here)
# Headers can define arity
{π aβΏb: a}1βΏ2 # and also do basic pattern matching
# (returns 1)
# Modifiers (higher order functions)
{π,π½,π,πΎ} # π½ and πΎ are the operands as callable functions
# π and π are the operands as values
{π½π©} # 1-modifiers use π½/π ONLY
Λ,Λ,Β¨,βΌ,β # primitive 1-modifiers are superscripts
{π¨π½πΎπ©} # 2-modifiers MUST use both π½/π and πΎ/π in body or header
βΈ,β,β,β # primitive 2-modifiers all have circles
+{β¨πβ©} # returns β¨ + β©
1-{π½ π¨ πΎ π© }Γ2 # returns Β―2 (operators are *also* infix)
# (same as 1 -βΓ 2)
# Trains (Special form of function composition)
(+´÷β ) # Average (but how?)
# The above train is an F G H train, where
# (F G H) π© β (F π©) G (H π©)
# F β +Β΄, G β Γ·, H β β
# In explicit form, this is
{(+Β΄π©)Γ·β π©}
# The second pattern is (f g) π© β f g π©.
# longer trains are complex arrangements of these patterns, involving constants and Nothing (Β·).
# Read more about trains at https://mlochbaum.github.io/BQN/doc/train.html
# Evaluation order:
# BQN evaluates functions right to left with no precedence rules governing *functions*. Functions are what
# one would call operators in a mainstream language.
1Γ·2+3 # 1Γ·(2+3) = 0.2
(1Γ·2)+3 # ((1Γ·2)+3) = 1.5
# Modifiers:
# Modifiers are higher order functions, and bind tighter than functions. Modifiers execute left to right.
# Modifiers can take non-function arguments e.g. Constant (`Λ`)
+
1+Λ2+β-βΓ3 # 1(+Λ)(2((+β-)βΓ)3)
# Variables
# Since the case of a variable matters to determine what it means, BQN variables are *case insensitive*
# The case that a variable is written in can change the way it is interpreted by BQN.
# Eg. `F` refers to a value as a callable function, whereas `f` refers to the same variable as just a value.
# Variable assignment is done with `β`. Variables have naming conventions based on their value:
subject β 1βΏ2βΏ3 # Arrays, single values, namespaces come under this
# name must start with with a lowercase letter
Function β {π¨+π©} # Primitive and user defined functions come under this, both monadic and dyadic
# Starts with an uppercase letter
_1modifier β {π¨π½π©} # Starts with an underscore
_2modifier_ β {π½π¨πΎπ©} # Starts and ends with an underscore
# Variable modification is done with `β©`. An existing name cannot be reassigned with `β`.
Func β© {"Hello"βΎπ©}
array_or_atom +β© 2 # You can use a dyadic function for modification
#β‘ 3βΏ4βΏ5
array_or_atom -β© # Or a monadic function.
#β‘ Β―3βΏΒ―4βΏΒ―5
# Due to all functions being infix, you can use your own functions for modification as well:
array_or_atom {2βπ©}β© #β‘ β¨ 0.125, 0.0625, 0.03125 β©
##################
# BQN Primitives #
##################
# All of BQN's base primitives are a single character long. Refer to https://mlochbaum.github.io/BQN/help/index.html for
# examples.
# Here we will look at a few primitives from each section. You will want to consult the docs for detailed explanations.
# Primitive Functions
# All BQN functions are variadic, and can take one or two arguments. The base functions have both monadic and dyadic overloads.
# Usually the two overloads for a function are related.
## Arithmetic Functions
+, -, Γ, Γ· # Add, Subtract, Signum/Multiply, Reciprocal/Divide , '*' does NOT do multiplication
# ββΓ· does floor division
β, β # Square root/Nth root, e^x/Power
# All Arithmetic functions vectorize:
1 + 2βΏ3βΏ4 #β‘ 3βΏ4βΏ5
1βΏ2βΏ3 + 2βΏ3βΏ4 #β‘ 3βΏ5βΏ7
# Character arithmetic(+ and - only):
"abc"+3 #β‘ "def"
'a'-'d' #β‘ Β―3
## Logic Functions
β§, β¨, Β¬ # For Booleans, return 1 or 0
β€, <, >, β₯, = # Vectorizing comparisons
β‘, β’ # Nonvectorizing comparisons
## Array manipulation Functions
β # Make a range
βΎ, β, β # Joining arrays together
aβ1βΏ2βΏ3,bβ4βΏ5 # Let us take a and b.
aβΎb #β‘ 1βΏ2βΏ3βΏ4βΏ5
aβb # Same as previous, since a and b are not multidimensional
# Adds an extra dimension, similar to a β for multidimensional arrays.
aβb #β‘ β¨1βΏ2βΏ3, 4βΏ5β©
β, β # Indexing
1β1βΏ2βΏ3 #β‘ 2 (BQN is 0-indexed)
1βΏ2β1βΏ2βΏ3 #β‘ 2βΏ3 (for multiple indices)
β, β # Getting a prefix, suffix of an array.
# together they can be used for slicing
β₯ # Reshape/repeat items to create a new array
# Primitive 1-Modifiers
## Looping combinators
Β¨, Λ, β # Mapping/Zipping
Β΄, Λ # Fold from right
` # Scan from left
## General combinators
Λ # duplicate argument/swap args - Very useful!
Λ # Create constant function
1 -Λ 2 #β‘ 2 - 1
+Λ 2 #β‘ 2 + 2
# Primitive 2-modifiers
## Control Flow
βΆ # Choose from a list of funcs
β # Repeat n times
## General Combinators
βΈ, β # hook, hookf
β, β # simple function composition
##########
# Blocks #
##########
# Code delimited by {}
# Lexically scoped
# For more info: https://mlochbaum.github.io/BQN/doc/block.html
# Can have headers, which are ways to explicitly define what a block should be.
# A block without headers is automatically inferred from its special variables (π¨, π©, ...).
# Function blocks
# Implicit variables(Capitals are functions):
# - π¨, π left argument
# - π©, π right argument
# - π€, π represent the block itself
# Optional: one or more headers that trigger based on
# - pattern match (':') o
# - condition ('?') (similar to if-then-else)
{ # A factorial using headers:
π 0: 1;
π π©: π©Γπ π©-1
}
{ # Factorial with predicates
π©<2 ? 1; # Similar to an if-else pattern.
π©Γπ π©-1
}
# Modifier blocks
# create 1-modifiers and 2-modifiers, which have separate types
# Implicit variables(Capitals are functions):
# - has π¨ and π© if needed
# - π, π½ left operand
# - π, πΎ right operand (only in 2-modifiers)
# - π£ represents the block itself* (requires underscores as per convention)
# Same header rules as functions.
{ π¨=0 ? π½ π©; πΎ π© } # execute π½ or πΎ based on whether left argument is 0.
# Namespace blocks
# Create immutable namespaces with fields
# Require exports (`β`) for accessible fields.
# Use '.' for field access
nβ{
Aβ+
bβ4
}
n.b #β‘ 4
n.a # ERROR
# Immediate Blocks
# No arguments taken
# Run the code inside and return the last statement
# Often responsible for strange errors.
# Can be mistaken for other blocks easily
# Good for avoiding scoping issues
{
1βΏ2βΏ3
}
{+} # Trick for returning a function as a value
####################
# Basic constructs #
####################
# Functional programming
# `Β¨` is used for mapping, as discussed before:
{π©βΎ2}Β¨1βΏ2βΏ3 #β‘ β¨1βΏ2,2βΏ2,3βΏ2β©
# βΒ¨ is a plain zip, which produces pairs.
# `Β¨` acts as a zipWith when used with two arguments:
1βΏ2βΏ3 {β¨π©+2,2β₯π¨β©} 4βΏ5βΏ6 #β‘ β¨β¨6,1βΏ1β©,β¨7,2βΏ2β©,β¨8,3βΏ3β©β©
# `/` is replicate, which serves several purposes *including* filtering.
# elements in π© are repeated by the corresponding number in π¨.
1βΏ2βΏ3βΏ0/4βΏ5βΏ6βΏ7 #β‘ 4βΏ5βΏ5βΏ6βΏ6βΏ6
# a simple filter idiom is FβΈ/:
{2|π©}βΈ/67βΏ42βΏ83 # keep the odd elements
#β‘ 67βΏ83
# Conditionals
# There are two main ways to define a conditional.
## Predicate headers
{
π© > 2: "greater than 2";
π© < 2: "lesser than 2";
"equal to 2"
}
## Choose (function-based)
# - 2-modifier
# - πΎ: list of functions that serve as bodies
# - π½: condition function that specifies which function from πΎ to select
# The same conditional as above would be:
{β/β¨π©>2, π©<2, π©=2β©}βΆβ¨
{π: "greater than 2"}
{π: "lesser than 2"}
{π: "equal to 2"}
β©
## Some helpers for conditionals
If β {πβπ@}Β΄ # Used as If β¨Condition, Blockβ©
IfElse β {cβΏTβΏF: cβΆFβΏT@} # Used as IfElse β¨Condition, Block, ElseBlockβ©
# Looping
# The primary form of unbounded looping is recursion (performed with π).
# BQN does not eliminate tail calls, but the while idiom can be used to work around this:
While β {π©{π½βπΎβπ½_π£_πΎβπ½βπΎπ©}π¨@}Β΄ # While 1βΏ{... to run forever
DoWhile β {π@ β While π¨βΏπ©}Β΄
# A For loop can be done with Β¨, functions need not be pure.
Got a suggestion? A correction, perhaps? Open an Issue on the GitHub Repo, or make a pull request yourself!
Originally contributed by Raghu Ranganathan, and updated by 3 contributors.