HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
tomprimozic
type-systems
OCaml2014–2019
tomprimozic / type-systems

type-systems

Implementations of various type systems in OCaml.

10Distinct people
19Mentions
0Explicit recommenders
1.6KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Implementations of various type systems in OCaml.

GitHub

Where it is used

No documented product use has been verified yet.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 3:03:16 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year19 dated mentions

Observed mentions: 2014-04-04 11:50:29 UTC to 2019-05-04 00:45:03 UTC.

0369122014-01-01 00:00:00 UTC to 2015-01-01 00:00:00 UTC (exclusive): 12 mentions; 3 submissions, 9 comments20142015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 2 mentions; 1 submissions, 1 comments2016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments20162017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2019

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20142014-01-01 00:00:00 UTC2015-01-01 00:00:00 UTC1239
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC211
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC101
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC101
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC202
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC101

What Hacker News says

19 sources
I wonder if coming from the other way would be acceptable for fans of dynamic typing. Instead of adding types gradually to a dynamic language (like Typescript sorta does with Javascript), we could add type-checking features that enable a kind of "statically-checked duck typing". Complete inference (like Elm, Crystal or Haskell) gets you halfway there – most of the time you don't have to write method/function signatures. Then add structural typing like Extensible Rows [1] or Elm Records [2], or something that type-checks based on the structure instead of classes, and it allows you to have the compile-time type-checking of Interfaces or Generics/Templates without the extra typing. Then you can add explicit generics/templates later if you want. Both Crystal and Elm get very close to that for me, but not 100%. I honestly think that this is a
Read the rest
safer bet than gradual typing that could lead to very similar results, but I don't know how feasible or acceptable to mainstream programmers this is. [1] https://github.com/tomprimozic/type-systems/tree/master/exte... [2] https://elm-lang.org/docs/records
In What to Know Before Debating Type Systems (2008)
I fundamentally disagree with the author's thesis. I don't think dependent types are the future of development, but instead I'd bet on refined types (or contracts - see my experiment [0], Liquid Haskell [1] by Ranjit Jhala, and languages Dafny [2] and F* [3] developed by Microsoft on top of Z3 SMT theorem prover [4]), where constraints are explicit yet simple, and proven automatically by an automated theorem prover. lookup : (a : array) -> (n : int if 0 <= n < length(a)) -> whatever [0] https://github.com/tomprimozic/type-systems/tree/master/refi... [1] https://ucsd-progsys.github.io/liquidhaskell-blog/ [2] https://rise4fun.com/Dafny/tutorial/guide [3] https://fstar-lang.org/tutorial - see e.g. section 3 "First proofs about functions on integers" [4] https://github.com/Z3Prover/z3
In Dependent Haskell
You're right, interesting example! Although I'd prefer to "fix" this by incorporating first-class polymorphism [1] with MLsub - I guess non-polymorphic functions satisfying the constraint `(a -> b) & (b -> c)` are quite rare (although I'm sure that you can think of an example). [1] https://github.com/tomprimozic/type-systems/tree/master/firs... Edit: although on second thought, just first-class polymorphism isn't enough to fix this... any type system where the function `twice` has the same type as the function `three_times` will exhibit the same problem!
In Algebraic Subtyping (2016) [pdf]
I understand static type annotations would be an extension to current Python semantics, it would require a flag such as "my type annotations are correct and please use them for optimizations" (this idea really only makes sense if PyPy can assume the annotations are not wrong, otherwise the arguments against this idea are just trivial). TypeScript is doing something similar for Javascript; it extends the language but is a strict superset. Type annotations can work together with JIT optimizations, because the annotations could simply provide a better starting point for JIT, requiring it to infer less, and perhaps providing information which would otherwise not be inferred from running the code. PyPy would still need to specialize further, e.g., from Int to int64 as you say, but already knowing that it's not float or str or list already seem
Read the rest
s useful. Gradual typing is relevant in this regard, which makes it possible to combine static and dynamic types and do type inference. See e.g. https://github.com/tomprimozic/type-systems/tree/master/grad... Now of course PyPy may hold the position that it's going to eschew static types on principle, but then it's a matter of ideology, not a technical reason, which causes these type annotations to "never have any value for PyPy".
In Mypy – static type checking for Python 3
> Why can’t we just allow polymorphic lambda-bound variables? Two reasons. The first is that in general, type inference for higher-rank polymorphism is undecidable. The second is that even if it were decidable, it would be impractical - I think that if we have a program like this one: let test(f) = (f(1), f(true)) the assumption that the programmer made an error is statistically much more likely than the assumption that `f` should have a polymorphic type. Another reason is that it's not entirely clear what kind of polymorphic type to infer for `f` - should it be `forall a. a -> a` or e.g. `forall a. a -> int`? > What does this have to do with different “ranks” of polymorphism? Higher-rank polymorphism means that polymorphic types can appear within other types; in a system with support for higher-rank polymorphic types, the parameter `f
Read the rest
` in the function `test` above could be declared with type `forall a. a -> a`, the function `test` would have a type `(forall a. a -> a) -> int * bool`. Higher-rank polymorphism is formalized using System F, and there are a few implementations of (incomplete, but decidable) type inference for it - see e.g. Daan Leijen's research page [1] about it, or my experimental implementation [2] of one of his papers. Higher-rank types also have some limited support in OCaml and Haskell. > How is let-polymorphism implemented? How do you implement it without just copying code around? The "standard" implementation consists of two operations, generalization and instantiation. At let bindings, types are generalized by replacing all unbound type variables with polymorphic type variables (care must be taken not to generalize type variables that can be bound later, but that's a secondary issue here). Every time a variable with a polymorphic type is used, its type is instantiated, which means that all polymorphic type variables are replaced with fresh unbound type variables. let f = fun x -> (x, x) print f(1), f("boo") In the example above, the type inferred for `fun x -> (x, x)` is `_a -> _a * _a`, where `_a` is an unbound (but not polymorphic) type variable. At let binding, this type is transformed into `forall a. a -> a * a` by replacing `_a` with a polymorphic type variable `a` (in most ML languages, the `forall` is implicit). Then, when `f` is used in `f(1)`, its type is instantiated into `_b -> _b * _b` and `_b` is unified with the type of `1`, `int`. When `f` is used in `f("boo")`, its type is instantiated into `_c -> _c * _c`, and `_c` is unified with type of `"boo"`, `string`. Since `_b` and `_c` are different variables, there is no error here (if `f` had a monomorphic type, `_b` and `_c` would in fact be the same, and this example would result in an error "cannot unify type int with type string"). > What’s the relationship between let enabling exponential function composition and the exponential time result? So there is quite a bit of copying happening every time a variable with polymorphic type is used. I've never studied the worst-case scenarios of Hindley-Milner, but I imagine that it has to do with instantiation copying large polymorphic types around. > Do implementations of Hindley-Milner actually represent types as dags and utilize structural sharing? Yes; an unbound type variable is typically represented as a reference cell, which is assigned to the type the type variable is unified with. So, if we have double : forall a. a -> a * a double (1, 1, 1) : (int * int * int) * (int * int * int) then the type of double is first instantiated, yielding `_b -> _b * _b`, and then the type of the parameter is unified with the type of the argument, `int * int * int`. At this point, the reference cell in the internal representation of `_b` is updated to point to `int * int * int`, which means that both `_b` in the result type actually point to the same representation of `int * int * int`. [1] http://research.microsoft.com/en-us/projects/fcp/ [2] https://github.com/tomprimozic/type-systems/tree/master/firs...
In Look at the humongous type that Hindley-Milner infers for this tiny program
In general, what you want to be able to mix types and values are dependent types (see languages such as Coq, Agda, Idris). However, dependent types are way too powerful, and as such extremely difficult to use. A light-weight form of dependent types are refined types, which are essentially dependent function types that have contracts on their parameters and return types. As refined types are way more limited than full dependent types (essentially, linear arithmetics, logic, and simple stuff like this), you don't always need to write the proofs manually but can use an automated theorem prover such as Z3. This is a hot research topic. There are attempts to do type inference for refined types - see [1] and [2]. The Liquid Haskell team is also exploring the issue of dependent types and laziness [3]. Below you mentioned that you want "soft cast
Read the rest
s" as well - check out [4], which attempts to do just that (implemented in language Sage [5]). I'm very interested in this topic as well, and have experimented a bit [6]; as it turns out, it's not that hard to implement a basic type-checker for simple refined types. It's also quite powerful - using Z3, even non-linear problems such as rectangular array access (mentioned by a poster below) are solvable, since you can trivially prove its safety using real arithmetics (which is decidable). The only big disadvantage that I see is the difficulty with dealing with state, but then again, even programmers can't reason about it properly; I mean, if `x` is a mutable object, can you really say `if x.a != 0 then 1 / 0` and be sure that no-one will modify `x.a` in the meantime from another thread? I hope that linear types could help. [1] http://goto.ucsd.edu/~rjhala/papers/liquid_types.pdf [2] https://www.cs.purdue.edu/homes/suresh/papers/vmcai13.pdf [3] http://goto.ucsd.edu/~nvazou/refinement_types_for_haskell.pd... [4] http://www.kennknowles.com/research/knowles-flanagan.toplas.... [5] http://sage.soe.ucsc.edu/sage-tr.pdf [6] https://github.com/tomprimozic/type-systems/tree/master/refi...
In Types Are The Truth
I hate to be the one to break it to you, but you did not invent the idea of reducing the good behavior of programs to first-order logic properties and to apply an SMT solver to these. You are not even at the point where you might compare your false-positive rate to their false-positive rate, but if someone was going to change the future with that idea, the future of 20 years ago would have been changed. And perhaps it was. But if SPARK83, to take one system amongst others, did not prevent Heartbleed, I don't see how your system “can prevent Heartbleed”. It can't, because Heartbleed is not written in the language at https://github.com/tomprimozic/type-systems/blob/master/refi... Describing your github repository with the words “can prevent Heartbleed” is disingenuous and unscientific. You should keep the dramatic hyperbole for the grant pr
Read the rest
oposals.
In Show HN: Simple refined types implementation that can prevent Heartbleed

Showing the 15 most recent of 19 sources. Enable JavaScript to search and browse every indexed mention.

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.