Thank you for your interest in contributing to T! This guide will help you get started.
We are committed to providing a welcoming and inclusive environment for all contributors, regardless of background or identity.
Violations can be reported to the project maintainers. All complaints will be reviewed and investigated.
Before submitting, check if the issue already exists in GitHub Issues.
When submitting: 1. Use a clear, descriptive title 2. Describe the exact steps to reproduce 3. Provide sample code and data (if applicable) 4. Include your environment (OS, Nix version, OCaml version) 5. Attach error messages and stack traces
Example:
**Bug**: `mean()` returns incorrect result for large floats
**Steps**:
1. Start REPL
2. Run: `mean([1e10, 1e10, 1e10])`
3. Expected: `1e10`, Got: `9.99999e9`
**Environment**:
- OS: Ubuntu 22.04
- Nix: 2.13.3
- OCaml: 4.14.1Before suggesting, consider: - Is it aligned with T’s design goals (reproducibility, explicitness, data analysis)? - Is it too broad or general-purpose? - Could it be a library instead of core language feature?
When suggesting: 1. Clearly describe the problem it solves 2. Provide concrete examples 3. Discuss alternatives 4. Consider backward compatibility
We welcome: - Bug fixes - New standard library functions - Performance improvements - Documentation improvements - Test coverage expansion
Good first issues are tagged with
good-first-issue in GitHub.
Documentation contributions are highly valued: - Fix typos and grammatical errors - Add examples to existing docs - Write tutorials for common workflows - Improve API reference clarity
See the Development Guide for detailed setup instructions.
Quick Start:
git clone https://github.com/b-rodrigues/tlang.git
cd tlang
nix develop
dune build
dune runtesttlang/
├── src/
│ ├── ast.ml # AST definition
│ ├── lexer.mll # Lexer (ocamllex)
│ ├── parser.mly # Parser (Menhir)
│ ├── eval.ml # Evaluator
│ ├── repl.ml # REPL implementation
│ ├── arrow/ # Arrow FFI bindings
│ │ ├── arrow_ffi.ml
│ │ └── arrow_stubs.c
│ ├── ffi/ # Other FFI utilities
│ └── packages/ # Standard library
│ ├── base/ # Errors, NA, assertions
│ ├── core/ # Functional utilities
│ ├── math/ # Math functions
│ ├── stats/ # Statistics
│ ├── dataframe/ # DataFrame operations
│ ├── colcraft/ # Data verbs
│ ├── pipeline/ # Pipeline introspection
│ └── explain/ # Debugging tools
├── tests/ # Test suite
│ ├── unit/ # Unit tests
│ ├── golden/ # Golden tests (T vs R)
│ └── examples/ # Example programs
├── docs/ # Documentation
├── examples/ # Example T programs
├── scripts/ # Development scripts
├── flake.nix # Nix flake configuration
├── dune-project # Dune configuration
└── Makefile # Convenience targets
Follow standard OCaml conventions:
Naming: - snake_case for functions and
variables - PascalCase for modules and types -
SCREAMING_CASE for constants
Formatting:
(* Use ocamlformat for automatic formatting *)
let eval env expr =
match expr with
| Int n -> VInt n
| Float f -> VFloat f
| Ident name -> Environment.lookup env name
| BinOp (op, left, right) ->
let v_left = eval env left in
let v_right = eval env right in
eval_binop op v_left v_right
| _ -> failwith "Not implemented"Comments: - Use (* OCaml comments *)
for implementation notes - Document complex logic - Explain “why” not
“what”
Pattern Matching: - Exhaustively match all cases -
Use _ for catch-all only when intentional - Avoid deeply
nested matches (extract functions)
Example programs should demonstrate best practices:
-- Good: Clear variable names, explicit NA handling
customers = read_csv("data.csv", clean_colnames = true)
avg_age = mean(customers.age, na_rm = true)
-- Bad: Cryptic names, implicit NA behavior
c = read_csv("data.csv")
a = mean(c.age) -- Errors if NA present
Documentation: - Include docstrings for new functions - Provide usage examples - Document parameters and return values
Located in tests/unit/.
Example (tests/unit/test_mean.ml):
let test_mean_basic () =
let result = Stats.mean [VInt 1; VInt 2; VInt 3] false in
assert (result = VFloat 2.0)
let test_mean_with_na () =
let result = Stats.mean [VInt 1; VNA NAInt; VInt 3] true in
assert (result = VFloat 2.0)
let tests = [
("mean_basic", test_mean_basic);
("mean_with_na", test_mean_with_na);
]Located in tests/golden/.
Compare T output against R:
T Program (tests/golden/mean.t):
print(mean([1, 2, 3, 4, 5]))
R Script (tests/golden/mean.R):
cat(mean(c(1, 2, 3, 4, 5)), "\n")Run:
dune exec src/repl.exe < tests/golden/mean.t > t_output.txt
Rscript tests/golden/mean.R > r_output.txt
diff t_output.txt r_output.txtRequired: - All new functions must have unit tests - Bug fixes must include regression tests - Performance claims must include benchmarks
Recommended: - Test edge cases (empty lists, NA values, errors) - Test cross-platform behavior (Linux, macOS) - Test integration with existing features
# All tests
dune runtest
# Specific test
dune runtest tests/unit/test_mean.ml
# Verbose output
dune runtest --verbose
# Watch mode (re-run on changes)
dune runtest --watchFork the repository
Clone your fork:
git clone https://github.com/YOUR_USERNAME/tlang.gitCreate a branch:
git checkout -b feature/my-featureMake changes:
Test:
dune build
dune runtestCommit:
git add .
git commit -m "Add feature: description"Push:
git push origin feature/my-featureOpen a Pull Request on GitHub
Follow conventional commit format:
<type>(<scope>): <subject>
<body>
<footer>
Types: - feat: New feature -
fix: Bug fix - docs: Documentation only -
style: Formatting, no code change - refactor:
Code refactor - test: Add or fix tests -
chore: Build, CI, tooling
Examples:
feat(stats): Add median function
Implements median via quantile(0.5). Supports na_rm parameter.
Closes #42
fix(eval): Fix closure environment capture
Closures were capturing global env instead of local env.
This caused incorrect behavior in nested functions.
Title: Clear and descriptive
Add median function to stats package
Description: Include: - What changed and why -
Related issue numbers (Fixes #42, Closes #17)
- Testing done - Screenshots (for UI/output changes)
Example:
## Summary
Adds `median()` function to stats package.
## Changes
- Implement median as `quantile(data, 0.5)`
- Add unit tests
- Update API reference documentation
## Testing
- Unit tests pass
- Golden test against R's `median()`
- Tested with NA values (na_rm parameter)
Fixes #42Checklist: - [ ] Code follows style guidelines - [ ] Tests added/updated - [ ] Documentation updated - [ ] All tests pass - [ ] Commit messages are clear
Choose a package: base,
core, math, stats,
dataframe, colcraft, pipeline, or
explain
Create function file:
src/packages/<package>/<function_name>.ml or
.t
Implement function:
(* src/packages/stats/median.ml *)
let median values na_rm =
Stats.quantile values 0.5 na_rmRegister in package loader (if needed)
Add tests:
tests/unit/test_median.ml
Update docs:
docs/api-reference.md
Add example:
examples/median_example.t
Parameters: - Required parameters first - Optional
parameters (e.g., na_rm) last - Use named arguments for
clarity
Return values: - Return values, not side effects
(when possible) - Use VError for errors, not OCaml
exceptions - Document return type in comments
Error handling:
(* Good: Return VError *)
if List.length values = 0 then
VError { code = "ValueError"; message = "Empty list"; ... }
else
(* Compute result *)
(* Bad: Raise exception *)
if List.length values = 0 then
failwith "Empty list"Include: - What you’re trying to do - What you’ve tried - Specific error messages - Minimal reproducible example - Your environment (OS, versions)
Example:
I'm trying to add a new window function `row_min()` but getting a type error:
Error: This expression has type 'a list but an expression was expected of type Vector.t
Code:
```ocaml
let row_min values =
(* ... *)I’ve looked at row_number.ml but can’t figure out where
the conversion happens.
Environment: Ubuntu 22.04, OCaml 4.14.1 ```
Contributors are recognized in: - GitHub contributor graph - Release
notes for significant contributions - CONTRIBUTORS.md file
(coming soon)
By contributing, you agree that your contributions will be licensed under the EUPL v1.2.
Ready to contribute? Check out good first issues or dive into the Development Guide!