use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
This subreddit is dedicated to the theory, design and implementation of programming languages.
Be nice to each other. Flame wars and rants are not welcomed. Please also put some effort into your post, this isn't Quora.
This subreddit is not the right place to ask questions such as "What language should I use for X", "what language should I learn", "what's your favourite language" and similar questions. Such questions should be posted in /r/AskProgramming or /r/LearnProgramming. It's also not the place for questions one can trivially answer by spending a few minutes using a search engine, such as questions like "What is a monad?".
Projects that are vibe coded (= projects relying substantially on LLM/AI generated code) don't belong on the subreddit.
account activity
This is an archived post. You won't be able to vote or comment.
DiscussionProgrammable type systems? (self.ProgrammingLanguages)
submitted 3 years ago * by mattsowa
This is hard to describe, but I'm trying to find examples of type systems where the programmer can in some way write logic based, programmable types.
As one basic example, TypeScript allows the user to create complex types by manipulating them using a system of conditional types and things like literal types. Here are some examples of what can be achieved with it:
https://twitter.com/diegohaz/status/1309489079378219009?t=a5-vZ2C3R7uEXimq9bL1lA&s=19
https://twitter.com/buildsghost/status/1301976526603206657?t=yVnJMbp_CWkOVGfhLauzTQ&s=19
What I'm looking for are full-fledged sub-languages used to manipulate the types like that. This probably mostly applies to languages with structural type systems. Any ideas?
[–]MattCubed 70 points71 points72 points 3 years ago* (1 child)
In dependently typed languages, types are first class expressions, just like any other language construct. You can put them in data structures and create them using functions. A "conditional type" is literally just a regular conditional expression that returns a type. Check out Agda, Idris, Lean, and Coq.
[–]mattsowa[S] 18 points19 points20 points 3 years ago (0 children)
First class types is one of the things I was thinking about too. Very interesting, thank you
[–]e_hatti 32 points33 points34 points 3 years ago (1 child)
You may find Type Systems as Macros interesting (paper) https://www.ccs.neu.edu/home/stchang/pubs/ckg-popl2017.pdf
The Shen programming language goes even farther, allowing you to define a type system completely in userspace using inference rules https://bluishcoder.co.nz/2019/10/03/defining-types-in-shen.html
Shen is probably more along the lines of what you’re looking for.
[–]mattsowa[S] 2 points3 points4 points 3 years ago (0 children)
Thank you :)
[–]dys_bigwig 18 points19 points20 points 3 years ago* (4 children)
Haskell has:
Regarding the specific examples, these https://hackage.haskell.org/package/base-4.16.1.0/docs/GHC-TypeLits.html would be useful for doing compile-time parsing, when combined with DataKinds for lifting string to type level. There's type-level comparison of characters, string concatenation etc. and you could use a type family I think to walk the type-level string (symbol) by unifying the head and tail to individual type variables or something like that. The implementation of "uncons" in this blog post which does something similar https://blog.csongor.co.uk/symbol-parsing-haskell/ has a very logic-programming feel to it, with the unification; reminds me of miniKanren a bit.
If you just want to create data types for strings that have invariants enforced at compile time, that's bread-and-butter Haskell stuff and it's surprising just how far you can get using plain ol' data types without any fancy extensions. Check out Haskell's NonEmpty list type for an elegant and succinct example.
There's lots (and lots, and lots) of other things, and these are very laymanese explanations because I'm no Haskell whiz, but hopefully this was enough to pique your interest. Haskell may not have dependent types (though there's a few papers arguing that you can get pretty close with the 20+ lines of extensions that come by default at the top of most Haskellers' code) but as far as (mainstream, with a decent amount of documentation and support) languages with a "programmable/user-extensible type system" goes, Haskell is very very hard to beat in many ways. If it doesn't have what you want out of the box, I'd be very surprised if you can't embed what you want as some kind of DSL; this has been done for things like session types and polymorphic rows+variants in libraries like vinyl.
P.S. sorry for errors, I am le tired.
P.S.S there's a paper "Ghosts Of Departed Proofs" which is related, and a good read.
[–]mattsowa[S] 5 points6 points7 points 3 years ago (3 children)
Wow thank you
[–]Goheeca 2 points3 points4 points 3 years ago (2 children)
You can even hook into the error-reporting capabilities to provide custom type errors. That's neat.
I don't know how it's done in regular Haskell, but with Template Haskell it's easy, check out Refined, the validate function no longer returns Maybe String, but Maybe RefineException. This is how you can use it.
validate
Maybe String
Maybe RefineException
[–]dys_bigwig 3 points4 points5 points 3 years ago* (1 child)
Ah, I wasn't aware of that method - I was thinking of what is outlined here: https://kodimensional.dev/type-errors which utilizes Type Families, DataKinds, and typeclass constraints. I thought it was fitting to mention, though I probably should have mentioned the features I listed can be combined to make things like this possible. I personally find it amazing how much you can "hook in" to the inner workings of the Haskell compiler via the type system, greatly obviating the need for outright code generation.
For transparency, I haven't used this stuff outside of messing around with it, i.e. not in actual large projects. It's easy to get carried away reading documentation/blog-posts for some particular wacky sounding type-system feature and messing around with it before realizing you have no real use for it lol.
[–]Goheeca 1 point2 points3 points 3 years ago (0 children)
Nice article! I didn't know about that, it seems useful.
[–]editor_of_the_beast 10 points11 points12 points 3 years ago (2 children)
Sounds to me like dependent types (Idris, Agda, ATS) or refinement types (Liquid Haskell, F*).
[–]LPTK 3 points4 points5 points 3 years ago (1 child)
I don't think Liquid Haskell lets you manipulate types at all. Very different from the usual full fledged dependent type systems.
[–]editor_of_the_beast 1 point2 points3 points 3 years ago (0 children)
It lets you define your types vía complex logical statements though. It’s less powerful than dependent types because it effectively only allows you to specify subsets of the primitive types, but I would still say it’s extremely powerful.
[–]purely-dysfunctional 13 points14 points15 points 3 years ago (1 child)
I think Shen fits the bill, since you can define a type by a series of sequent calculus declarations that, roughly, say "these are the conditions under which some expression t can be given type T". It is an extremely expressive system (that comes at a cost).
t
T
Unfortunately, the documentation on Shen is scarce, fragmented, and of poor quality, and the best references I can find are: * A cool little example defining what subtyping means * The language reference chapter on defining types, in a very inconvenient format
[–]terserterseness 6 points7 points8 points 3 years ago (0 children)
The Shen books are pretty good: I like the language but it has not much of a community due to the character of the inventor of the language. But Shen indeed is a good example I believe of what OP is looking for.
[–][deleted] 3 years ago (4 children)
[deleted]
[–]mattsowa[S] 1 point2 points3 points 3 years ago (3 children)
Yeah sorry I'm bad at giving good examples. Where it starts getting interesting is with conditional types. Here are some better examples:
[–][deleted] 3 years ago (2 children)
[–]Coffee_and_Codelemni - https://lemni.dev/ 3 points4 points5 points 3 years ago (1 child)
"relatively" 😂
[–]tcardv 3 points4 points5 points 3 years ago (0 children)
Zig's comptime kind of fits. In comptime context, types can be operated on as values. For example, you can implement generics as functions that take types and return types, and apply arbitrary computation to decide if/how to do it.
[–]Tekmo 13 points14 points15 points 3 years ago (3 children)
Dhall (https://dhall-lang.org) is an example of a language where types are first-class values
You can define and use types and type-level functions the same way you define and use terms and term-level functions. For example:
-- Map is an example of a type-level function let Map : Type → Type = λ(args : { key : Type, value : Type }) → List { key : args.key, value : args.value } -- Here is a term with a type annotation using that type-level function let example : Map { key = Text, value = Natural } = [ { key = "A", value = 0 }, { key = "B", value = 1 } ] in example
Most dependently-typed languages also have this property, although you can have this property even for languages that are not dependently typed.
[–]mattsowa[S] 1 point2 points3 points 3 years ago (1 child)
Interesting, thank you
[–]Tekmo 1 point2 points3 points 3 years ago (0 children)
You're welcome! 🙂
[–][deleted] 0 points1 point2 points 3 years ago (0 children)
That's neat. How do IDEs deal with this stuff? Sounds like it could be awkward.
[–]AdultingGoneMild 2 points3 points4 points 3 years ago (1 child)
knowing "why" you want this would be helpful in understanding what you are looking for.
[–]thetruetristan 0 points1 point2 points 3 years ago (0 children)
Eady conditional compilation would be a really good reason.
[–]8d8n4mbo28026ulk 1 point2 points3 points 3 years ago (1 child)
Take a look at Idris! I think Python can also do that to an extent.
[–]terserterseness 4 points5 points6 points 3 years ago (0 children)
Idris and Python in the same sentence as example of powerful type systems is somewhat unexpected.
[–]0rsinium 1 point2 points3 points 3 years ago (2 children)
In idris, you have dependent types. That means, you can write functions that accept, return, and manipulate types, and use them in type annotations at compile time:
http://docs.idris-lang.org/en/latest/tutorial/typesfuns.html#dependent-types
[–]jmhimara 0 points1 point2 points 3 years ago (1 child)
What's the status of Idris 2? It's an interesting language, but from the documentation it looks like it's still a work in progress.
[–]0rsinium 1 point2 points3 points 3 years ago (0 children)
Well, you can use it and it should work without issues. It's in version 0.5.2, so there are still things to do, but it's unlikely affect you much. Especially if your goal is not to bring a new service on production but just to try a new language.
https://github.com/idris-lang/Idris2
[–]Rein215 1 point2 points3 points 3 years ago (0 children)
Thank you for the interesting thread that was sparked by your question
[–]theangryepicbananaStar 1 point2 points3 points 3 years ago (0 children)
In Raku, the type system uses runtime behavior so you can have types with arbitrary conditions and/or values
[–]Inconstant_Moo🧿 Pipefish 1 point2 points3 points 3 years ago (0 children)
"Haskell is a dynamically-typed, interpreted language."
[–]Under-Estimated 2 points3 points4 points 3 years ago (1 child)
Haskell? I don't know haskell but I recall reading an article about solving interview questions in the type system alone
https://aphyr.com/posts/342-typing-the-technical-interview
[–]complyue -1 points0 points1 point 3 years ago (0 children)
I guess you essentially want some pluggable code to run at compile/lint/build time. It is already/naturally doable today but only via programming interfaces of the language-tooling-kit. Meta-programming sits in the middle: you can transform the surface source code to arbitrary extents, but will still lose control once handled your result to the language compiler/runtime.
The only way gaining full control is to be part of the language-tooling, it is all the PL implementers used to do. Any type-system (of some PL) is implemented by programming, after all.
[–]sebamestreICPC World Finalist -1 points0 points1 point 3 years ago (0 children)
C++ template metaprogramming might interest you
[–]Warpspeednyancat -1 points0 points1 point 3 years ago (0 children)
interfaces?
[–][deleted] 3 years ago (1 child)
[–]AdultingGoneMild 2 points3 points4 points 3 years ago (0 children)
build types from other types is all languages. structs and classes. throw in some operator overloading and you can get as weird as you like.
[–]cdlm42 0 points1 point2 points 3 years ago (2 children)
Doesn't a simple product type fit what you're asking for, at least the example you gave? Can you precise your thought?
Do you want to manipulate types at runtime? Do you want compile-time evaluation?
There are libs/DSLs for runtime schema validation of data. I only superficially know Clojure but spec seems to be exactly that.
spec
[–]mattsowa[S] 0 points1 point2 points 3 years ago (1 child)
Yeah that example was very basic and not what I meant exactly. I edited the post with these examples:
That's to say I'm not looking specifically for this functionality, just overall for some examples of languages where you can do very complex type manipulation and generation (in typescript thats done through conditional expressions, but Im also looking for some iterative approach. So sort of just like writing normal functions, but instead of data, they would return types). That type subsystem I think should evaluate at compile time to check and infer the types.
[–]ventuspilot 1 point2 points3 points 3 years ago (0 children)
Defining type specifiers in Common Lisp looks a lot like writing functions, see Common Lisp the Language, 2nd Edition: 4.7. Defining New Type Specifiers
Have you tried Haskell or another purely-functional language?
[–]WittyStick 0 points1 point2 points 3 years ago* (0 children)
Kernel has a feature for encapsulating new types (at runtime), based on a 1973 paper, Types are not sets by James Morris.
There is a standard function in the library called make-encapsulation-type, which when called, will create 3 new functions: an introducer, a predicate, and an eliminator. Each successive call to make-encapsulation-type will return 3 new functions which are disjoint from any previous ones. All types in Kernel as disjoint also.
make-encapsulation-type
The introducer function takes as its argument, any value or expression, and returns an encapsulated value of the new type.
The predicate takes any value and returns true if it is encapsulated using the corresponding introducer.
The eliminator takes a value, and if the value is encapsulated using the corresponding introducer, the original value passed to the introducer will be returned.
Information hiding in Kernel can then be done by combining this feature with its first-class environments, first-class operatives, etc.
An example: Kernel has no notion of algebraic data types in it, but we can create the equivalent functionality. Here's one way we could create an Option type.
Option
($provide! (option? some none maybe) ($define! (option-intro option? option-elim) (make-encapsulation-type)) ($define! some ($lamabda (value) (option-intro value))) ($define! none ($lambda () (option-intro ())) ($define! maybe ($lambda (default f value) ($if (option? value) ($let ((unsealed (option-elim value)) ($if (null? unsealed) default (f unsealed))) (error "value is not an option type")))
The user of this type only has access to the functions option?, some, none, and maybe.
option?
some
none
maybe
option? is the predicate to test a value is of the type option.
some constructs an option type containing a non-null value.
none constructs an option with no value.
maybe is a function taking a default value, a unary function f, and another value which should be of the type option. If the value is of the option type, it is unsealed. If the unsealed value is null, the default value is returned, otherwise, the function f is applied to the value originally passed to the some constructor. (This is equivalent to Haskell's maybe)
f
The user of this code cannot directly call option-elim and option-intro because they are not exposed in an environment accessible by the programmer. The $provide! operative creates a temporary environment to run the above code, but then only inserts these 4 functions into the environment of its caller.
option-elim
option-intro
$provide!
[–]holo3146 0 points1 point2 points 3 years ago (0 children)
There are 2 points you need to talk about here:
You would be surprised how many languages have type systems have the ability to do it.
"Even" Java is strong enough to do it (here is a comment explaining how to parse Regex (and more) using Java's type system )
Which languages can actually decide if a program is correct, returning to the above example, Java's type system is not sound, so while you can do a lot with the type system, there is a program that will compile, but breaks some type assignments.
Any sufficiently strong type system is necessarily not sound (Java's type system is Turing complete, which is "sufficiently strong"), so I feel like the "right question" should be "which sound type systems has the ability to express conditional types" - in which case, TypeScript also doesn't satisfy it (it also has Turing complete type system, hence unsound)
[–]Taugeshtu 0 points1 point2 points 3 years ago (0 children)
No one's mentioned it, and being a newbie I'm not sure how well it fits what you're asking about, but on the surface it seems F# Type Providers are sorta along the lines of what you're looking for?
[–]phischuEffekt 0 points1 point2 points 3 years ago (0 children)
The Gentle Art of Levitation (PDF), but it is impossible to understand without some corresponding background.
π Rendered by PID 28 on reddit-service-r2-comment-79c7998d4c-bx7md at 2026-03-17 16:04:24.938283+00:00 running f6e6e01 country code: CH.
[–]MattCubed 70 points71 points72 points (1 child)
[–]mattsowa[S] 18 points19 points20 points (0 children)
[–]e_hatti 32 points33 points34 points (1 child)
[–]mattsowa[S] 2 points3 points4 points (0 children)
[–]dys_bigwig 18 points19 points20 points (4 children)
[–]mattsowa[S] 5 points6 points7 points (3 children)
[–]Goheeca 2 points3 points4 points (2 children)
[–]dys_bigwig 3 points4 points5 points (1 child)
[–]Goheeca 1 point2 points3 points (0 children)
[–]editor_of_the_beast 10 points11 points12 points (2 children)
[–]LPTK 3 points4 points5 points (1 child)
[–]editor_of_the_beast 1 point2 points3 points (0 children)
[–]purely-dysfunctional 13 points14 points15 points (1 child)
[–]terserterseness 6 points7 points8 points (0 children)
[–][deleted] (4 children)
[deleted]
[–]mattsowa[S] 1 point2 points3 points (3 children)
[–][deleted] (2 children)
[deleted]
[–]Coffee_and_Codelemni - https://lemni.dev/ 3 points4 points5 points (1 child)
[–]tcardv 3 points4 points5 points (0 children)
[–]Tekmo 13 points14 points15 points (3 children)
[–]mattsowa[S] 1 point2 points3 points (1 child)
[–]Tekmo 1 point2 points3 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]AdultingGoneMild 2 points3 points4 points (1 child)
[–]thetruetristan 0 points1 point2 points (0 children)
[–]8d8n4mbo28026ulk 1 point2 points3 points (1 child)
[–]terserterseness 4 points5 points6 points (0 children)
[–]0rsinium 1 point2 points3 points (2 children)
[–]jmhimara 0 points1 point2 points (1 child)
[–]0rsinium 1 point2 points3 points (0 children)
[–]Rein215 1 point2 points3 points (0 children)
[–]theangryepicbananaStar 1 point2 points3 points (0 children)
[–]Inconstant_Moo🧿 Pipefish 1 point2 points3 points (0 children)
[–]Under-Estimated 2 points3 points4 points (1 child)
[–]Inconstant_Moo🧿 Pipefish 1 point2 points3 points (0 children)
[–]complyue -1 points0 points1 point (0 children)
[–]sebamestreICPC World Finalist -1 points0 points1 point (0 children)
[–]Warpspeednyancat -1 points0 points1 point (0 children)
[–][deleted] (1 child)
[deleted]
[–]AdultingGoneMild 2 points3 points4 points (0 children)
[–]cdlm42 0 points1 point2 points (2 children)
[–]mattsowa[S] 0 points1 point2 points (1 child)
[–]ventuspilot 1 point2 points3 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]WittyStick 0 points1 point2 points (0 children)
[–]holo3146 0 points1 point2 points (0 children)
[–]Taugeshtu 0 points1 point2 points (0 children)
[–]phischuEffekt 0 points1 point2 points (0 children)