Miranda: First Impressions of a Haskellite
Miranda, the precursor to Haskell, has recently been released as open source. I took the opportunity to try it out with a little side project I’ve been floating around to myself for a while.
These are my first impressions.
Syntactically, Miranda has a similar feel to Haskell, as would be expected. There are some striking differences, some of which are quite limiting.
There is no allowance for
_ as the first (or only) character of an identifier, which makes quickly marking out intentionally unused variables hard. There are no case expressions, so pattern matching of intermediate return values can only be done with helper functions. Comments are indicated with a
|| prefix and terminated with a newline; the boolean ‘or’ operator is
Equality checks can be done with either of
=, and, as far as I can tell, these have identical behaviour in the context of conditional expressions. Talking of conditionals, Miranda offers no standalone
if control flow construct;
ifs are only used as a prefix to a conditional where a guard clause would be used, like so:
foo a = a, if a < 0
= a * 2, otherwise
Whitespace is significant, and it feels noticeably less flexible to me than Haskell, but I can’t prove that. This is not necessarily a bad thing.
There are a fair few oddities. The one standout syntactic oddity to me is the operator-like functions,
div (integer division) and
mod (modulus), which act like operators, but don’t look like it. You use
div, for example, like
x div y; you can’t use it like
div x y. If you partially apply it, it acts like an operator section, such as in
map (div y) xs.
Miranda has a lot of semantics you might expect from a precursor to Haskell.
The parametrically polymorphic Hindley-Milner type system with advanced type inference is there, pattern matching, higher order functions, automatic currying, non-strictness, and something I didn’t expect: list comprehensions.
Something which I really didn’t expect is that Miranda is full of impure workarounds. I knew that, even in Haskell, IO was not done with a monadic interface until Haskell 1.3, and I had a vague idea that before that,
main in Haskell involved a list of IO requests. From what I can now gather,
main wasn’t just a
[Request], but a
[Response] -> [Request]; requests could be made based on previous responses, and the laziness of the response list and request list made this possible.
I expected Miranda to do IO using a similar mechanic. I learnt that
main in Miranda could be any type and it would behave in one of three ways, depending on its type:
- if it were a
[sys_message] — which is essentially a list of IO requests — Miranda would evaluate each
sys_message in turn,
- if it were a
string, Miranda would print it directly to the console, and
- if it were anything else, Miranda would apply
show to it and print the resulting string.
[sys_message] was the equivalent to Haskell’s pre-monadic IO
main. At that time, I didn’t recall that
main in Haskell pre-monadic IO was a function that took a list of responses and returned requests, not just a straight list of requests. I scoured the Miranda documentation trying to figure out how to use the return value of a
sys_message request made earlier to determine what
sys_message request to make next.
After noticing that the set of possible
sys_message values were only output-oriented and were in section 31/2 of the Miranda manual — “UNIX/Miranda system interface” ➤ “Output to UNIX files etc” — it dawned on me that this isn’t possible, and the only way to write programs that get input is to use the copious number of magic impure keywords and functions for that purpose:
getenv (notably, no
num to these hacks
Integers and floats are different types on the value level but not the type level. There’s a
num type, which
1.0 share, but
integer 1 = True and
integer 1.0 = False.
I haven’t yet gotten to the stage where I absolutely can’t make do without typeclasses or some analogous feature. I’ve had a look at the documentation, and
%include look like half promising candidates to look further into.
In the meantime, so far, I’ve had to write the functor, applicative, and monad functions separately for each type I use them for (for lists and custom types).
Miranda has a magic
show function, which returns a string representation of any value given to it.
There’s almost no tooling to speak of.
There is no package manager nor ecosystem of packages I’m aware of, and I haven’t yet found any community.
Vim recognises files with a
.m extension as Matlab files by default. I found a Miranda syntax highlighter at github.com/zlahham/vim-miranda which comes with an
ftdetect for Miranda and sets files with
.m extension to be detected as Miranda files.
It works okay, but it doesn’t cover all of Miranda’s syntax. I noticed that single quotes change the syntax highlighting immediately, even if they are being validly used in the middle or end of an identifier.
mira is a script-oriented interpreter. The documentation refers to Miranda programs as scripts everywhere. There is no option to compile to native code, only bytecode which is then either executed or loaded into a REPL. Miranda, the language, is pretty small, too, and well suited for scripting. To understand how small, this is the full list of values and types in the standard environment:
Appendfile Appendfileb Closefile Exit Stderr Stdout Stdoutb System Tofile Tofileb abs and arctan cjustify code concat const converse cos decode digit drop dropwhile e entier error exp filemode filestat filter foldl foldl1 foldr foldr1 force fst getenv hd hugenum id index init integer iterate last lay layn letter limit lines ljustify log log10 map map2 max max2 member merge min min2 mkset neg numval or pi postfix product read readb rep repeat reverse rjustify scan seq showfloat showhex shownum showoct showscaled sin snd sort spaces sqrt subtract sum sys_message system take takewhile tinynum tl transpose undef until zip zip2 zip3 zip4 zip5 zip6
I believe the only identifiers missing from that list are the primitive types
num. The only non-primitive type is
sys_message, which has the constructors
Appendfile Appendfileb Closefile Exit Stderr Stdout Stdoutb System Tofile Tofileb already listed above.
Running a Miranda file with a
.m extension results in
mira creating matching bytecode versions with
.x extensions for each file it compiles (the entrypoint and included files). To solve this problem and just allow single executable scripts, I created
mirapack, only to later found out that
mira doesn’t create these bytecode files if the Miranda file doesn’t end in a
.m extension, but
mira -exec still works (it can have no extension or an extension that’s not
.m). I had initially thought the bytecode files were created regardless of extension because the
miralib directory came with a
preludx file (these contain internal implementation for parts of
-exec) on a file that doesn’t exist enters a REPL session with that file as the script, and if the file doesn’t have a
mira will add a
.m extension to the filename it sets as the session’s script, even if the file exists without the
mirapack is also still useful for when you want to bundle a small project with
%include directives into a single executable.
One small quality of life improvement I’d make to
mira would be to print error messages even after a repeated build of the same files.
Size and performance
Compiler and standard library
As I pointed out just a little earlier, Miranda comes with a compact standard library. On my machine, the
mira binary itself clocks in at ~236K, a little over 10% (~11%) of GHC 8.4.4’s binary size of ~2M; this is more than I expected considering how much fewer features it has. Still,
stdenv.m with documentation stripped out (it’s a literate file) is ~6K.
stdenv.x is ~5.8K, and GHC’s
base-188.8.131.52 (compiled) is ~92M.
Far more important than size to me is performance. This is where all the lack of features becomes a feature in itself. I’ve been using GHC for a long time, and I started to get a frustrated with the compile times. This blog runs on Hakyll, and every time I push a new commit, the CD build takes ~40 minutes (my CD provider doesn’t cache builds).
I don’t mean to put down the work of GHC maintainers at all. It’s an incredible compiler with a lot of high impact benefits and it’s stuck around where other Haskell98 or Haskell2010 compilers haven’t, but being the only viable Haskell compiler around, it also has to work for a broad range of usecases. Advanced type system features of GHC may affect compile times despite not being active for a given project.
I’ve even gone as far as to learn OCaml for its fast compilation times, despite having avoided it for a long time due to its off-putting (to me) syntax; after a little while, my eyes got used to the syntax, but snappiness in software is always a priority for me. Alas, OCaml doesn’t mandate a pure functional style (though it does encourage it). Of course, even Haskell has escape hatches like
unsafePerformIO, but it goes much further than OCaml to discourage their use (such as having
main be a pure description of an impure program built up with pure functions).
mira is interpreted, there’s no native code output to measure the performance or size of, so build performance and runtime performance are essentially the same.
mira comes with a runtime, and so does GHC. GHC comes with an amazing green threads implementation and STM, to name just a couple of genuinely widely useful features, which can have a noticeable impact on GHC’s startup times.
It may sound silly to care about a ~300ms startup time when using
runhaskell, for example (which is what you want when you’re writing scripts), but I feel it, and snappiness isn’t just a problem for hello world in Haskell. I’ve already mentioned that this blog running on Hakyll takes ~30–40 minutes for the CD build to publish a post (although an installation of LaTeX is involved in that to build my CV, before that, the blog took even longer to build; ~55 minutes, in fact).
The culture around Haskell doesn’t seem to care enough about snappiness to make it a priority. That’s perfectly fine, of course, it’s just not for me. I can live with it in larger projects, using tools like
stack build --fast, but for small scripts, it’s subjectively painful for me. Even for larger projects, where
stack build --fast are a big help, they only help so much.
Writing small purely functional scripts is a big reason I wanted to try Miranda — small scripts I could put into my home
bin directory for dotfiles glue and so on. In this context, startup time matters more than usual. I think pure functional programming lends itself well to scripting, but for the life of me, I can’t figure out a practical way to do it with today’s languages and tooling.
In the end, what I was looking for in Miranda was a pure functional programming language that I could use for scripting. From what little I’ve used Miranda, it hits the scriptability criterion, but not the pure functional criterion.
I can’t say I was expecting much. Even if it had been pure, a
main :: [Request] -> [Response] would’ve been a massive pain in the ass. That said, I was hoping to be pleasantly surprised.
My thoughts on Cassie Jaye's “The Red Pill”
I went to see Cassie Jaye’s documentary, “The Red Pill”, a couple of weeks ago now (19 November, International Men’s Day) with a friend and brother. This is less a review, and more me recounting my experience without spoiling the movie in any major way. Disclaimer: I backed the movie on Kickstarter.
I travelled out to London to see it. It was supposed to start screening at 6 o’clock in the evening, but there was a period of confusion for everybody for an hour and a half, as the film only started playing at 7:30. I’m not sure who was responsible for the screening, but that was a bummer (though not really a fault of the movie). I only mention it to make the point that if you’re going to a screening, keep in mind that they’re not all made equal. This was a really low-key venue situated in South East London. It was small and inconspicuous - not all that official. There was no Q&A segment, no appearances by Erin Pizzey, Cassie Jaye, or Warren Farrell, all of whom had attended other screenings.
Once we got past that hump, the movie began.
I guess the first thing I have to mention is that it did not go into a lot of the stories/interviews in the trailer, which I wasn’t expecting. I still really enjoyed the movie, but I was looking forward to seeing some of those narratives expanded in the movie. There’s a really moving part in the trailer where a man talking about his experiences suddenly stands up and is visibly upset, saying, “I don’t like sympathy for any of this stuff”. That said, there were also parts featured in the movie that I know a lot of people (including myself) were hoping to see — such as the interview with Karen Straughan (GirlWritesWhat) — that weren’t in the trailer. I really hope all the footage is released to the public some day. I think it could prove very valuable.
I think Karen Straughan really made palpable the hypocrisies of feminism with regards to language control. As always, she was very articulate and makes these connections that are clear after the fact, but few people think about before she points them out. She’s very good at spotting distant inconsistencies, which is a skill I really appreciate.
I don’t know what kind of footage we missed, but the stories that were shown were so compelling and infuriating (Fred Hayward’s experience with losing his son comes to mind in particular). Overall, I think Cassie did really well with the editing.
I really enjoyed the video diaries, and I think they added an interesting and convincing dimension to the movie. The diaries offered a chance to see Jaye’s internal struggle with her own long-held beliefs. As the film progresses we begin to see her attempt to resist change and double-down on her feminist belief system by leaning on her friends and feminist groups as she realises she is losing a part of her identity. This will send a clear message to any feminist (or non-feminist) who watches the film, I hope.
There was a no-holds-barred scene when talking about one particular issue, footage that came as a bit of a shock, but I’m really glad she showed it. It really forces the viewer to be confronted with the unfiltered truth right in front of them. There was no warning, and an audible groan from the audience shows that it did its job.
After the movie, I stayed and chatted with members of the audience for quite a while. A lot of people there had already taken the red pill, which was quite disappointing to me, as it essentially meant the movie was just preaching to the choir. I had hoped for a bigger turnout by blue pill people, but I guess that’s to be expected before the general release on places like Netflix, iTunes, Amazon, etc. That will be a big boon for getting the message to people who haven’t heard about the issues, or even those that have, but have not yet come into contact with some of the case studies, statistics and arguments made in the film.
The movie wasn’t made for people like me; it was a good primer into a lot of the common issues, but the rabbit hole, as they say, goes so much deeper. As someone who’s been involved with the movement for a long time, mostly through regular donations and mostly anonymous discussion online and raising the issues whenever they are relevant offline (i.e., more advocacy than activism), I already knew about all of the issues raised in the movie, barring some individual interviewee’s stories. I often want to start talking about some of the stuff you discover deeper in, and I think Cassie did a really good job tailoring this to people new to the issues (but obviously I don’t say this from a noob’s perspective).
As I said earlier, most people there were already red pill, but there was one person there (a self-proclaimed freelance journalist) who came in with opposing ideas about the movement to write an article about the movie. It’s sad that I have to say this, but props to that person for actually going to see opposing ideas and staying behind to have a discussion, instead of just signing a petition to stop the screening. In the midst of the group discussion, some points they made slipped through the net, which I will take the time to address here. I gather they were a feminist, but I don’t recall if they explicitly said so. I had a much more interesting and engaging conversation with the feminist than the other people there, incidentally. Listening to my own opinions echoed back to me has never been my idea of a good time.
The first thing was that a particular video diary looked really staged, and to be honest, I wouldn’t entirely disagree. I had the same thought during that particular video diary while watching it. It seemed like less of a structured diary entry (which you’d expect to be planned) and more a recording that was supposed to look unplanned, but didn’t. All I can say to that is that it’s not really a counter to the issues raised and the validity of the arguments, and it’s very subjective (and a low shot, but I think in good faith during a casual conversation). Cassie is a director, it’s not unusual that she would keep high production value video diaries, and it’s not unusual that a few of them would look staged as a result of that (and technically are, in a way).
The other thing the feminist mentioned was that the movie touched on the extreme rhetoric often employed by AVfM, the biggest men’s rights site on the web (disclaimer: I am a regular donator), but never really addressed them. I would have liked to see more of that addressed too and give them a chance to defend themselves, just to show the all the ways in which a lot of feminists and the mainstream media try to twist and distort and take out of context what he says. Alas, that would take a whole movie in its own right, and probably not one a lot of people would watch by choice. They did address one article in particular, “Bash a Violent Bitch Month”, noting that it was a satirical response to a Jezebel article, “Have You Ever Beat Up A Boyfriend? Cause, Uh, We Have”, which I think is enough to plant doubt into people’s minds about and trigger their own research. That said, it would have been nice to hear from Paul Elam directly, who was interviewed and have a quick 30-90 second explanation directly from the owner of the site.
The feminist also raised the issue of the movie seeming biased (noting the avoidance of challenging the extreme AVfM rhetoric as evidence for this). This movie is about one feminist’s journey into the men’s rights movement, who have an alternative perspective on gender issues. Cassie herself notes that she focused on the MRM as it has been so often ignored, maligned, and distorted by the mainstream media. That it focused predominantly on letting the people of that movement speak for themselves shouldn’t be surprising, and is, I think, fair. Cassie did give some air time to feminists to speak too, as she should have, and there would have been more feminist voices had David Futrelle (and others) not declined to speak with her after his smear campaign of Cassie when he found out that she was becoming sympathetic to the MRM and that the movie wasn’t going to be an attack on it.
The other thing pointed to as evidence of the bias is the focus on “baying crowds” of feminists juxtaposed with interviews with MRAs. As mentioned before, the film has a focus on the MRM’s platform, as most everyone knows much more about the feminist platform than they do the MRM’s. It’s not like Cassie completely avoided the “extreme” things people like AVfM in particular have written. In fact, the movie opens with a bunch of really extreme headlines and article snippets from AVfM, and as I said, she addresses one of those articles later in the film which plants the first seed of doubt about previous feminist responses to them. Feminists were given a chance to speak as well. All Cassie did was document (as a documentarian should) the facts. If reality has a bias, that’s not a failing of the messenger.
This bit has nothing to do with the film, but I have to address it because it’s so funny how it whizzed right past me at the time. I started talking about the “violence against women” line and how violence is perpetrated much more against men, and how we often avoid perpetrating violence against women for the sole reason that the would-be victim is a woman. I talked about my experiences with violence as a man and how it’s so normal that you don’t even think about it as a problem, but rather as something that’s just there that people try to avoid imposing on women. They started talking about how, after starting their transition to being a woman, they noticed a difference in the way people treated them, and in fact, they started being targeted for violence; they specifically mentioned an incident in which a stranger chased after them and called them a “fag”. I didn’t even think about that little extra line, but looking back on the conversation later, I think their experience proves my point. Clearly, in the eyes of this person that targeted them, they were still a man (and in this case, they still spoke and (mostly) appeared to be a man). That the person shouted “fag” demonstrates that the person I was talking to was being targeted for being a homosexual man (whether they were or not is beside the point).
Anyway, to get back to the film, all in all, I think it’s a great primer to the MRM for people who are ignorant of the issues and I really hope it gets wide distribution. I hope it opens up a wider discussion about men’s issues, and the problems with feminism, some of it inherent. I think Cassie and the team did a great job, and I really want to thank them for putting their careers and personal relationships on the line to share the journey. I know Cassie has lost friends because of this movie, and I don’t take that lightly. Thank you, Cassie! Thank you to her boyfriend for being willing to challenge her on her feminist beliefs.
I really believe this film marks a turning point in mainstream acceptance of MRM ideas. I think the excesses of feminism has accelerated this process and they only have themselves to blame. I have heard that several feminists have really been given pause after watching this film, and I hope that continues to happen.
Pitfalls to avoid when writing multiprocess Ruby code
So, a couple of weeks ago, I wrote a post on how fast forking can make your MRI Ruby code. There are a few things to be aware of, though, before you go out and take advantage of this.
Obviously, your code has to be thread-safe. I can’t tell you if your Rails app is thread-safe or not, but this Bear Metal blog post might be helpful.
The first pitfall I experienced was ActiveRecord. If you fork, you must use a different connection per process. I cannot recall the exact error message that you would get if you did not use a new connection (and I no longer have access to the codebase to quickly check that, nor am I going to start up a new Rails app to check).
I was writing a short-lived process, and simply saying
ActiveRecord::Base.connection.reconnect! in the fork block was fine, up until I needed to test the code with RSpec. Then, I had to change the process to disconnect from the main process, establish a new connection for each subprocess (in the fork block), and then establish another new connection in the main process, which I did after waiting for all the child processes to finish.
Speaking of waiting for child processes, the second pitfall was tricky. I used
Process.waitall2 to indiscriminately wait for all the child processes. Of course, that was fine, since it was a short-lived process started from a Rake task, but once I needed to test that code, it started interacting with other code, some of which could also start their own child processes. In my case, we were using a gem called
sunspot-rails-tester, which started a Sunspot process for integration tests. The problem here was two-fold.
First of all,
Process.waitall2 was waiting for a never-ending child process to end. Changing that to simply
Process.waitpid2 pid on each of my child process IDs fixed the problem with my test taking forever (literally) to finish until an outside force stopped them. That’s a strike against imperative-style global variables (of course, there was no variable involved here per se, but this is analogous to saying
Process.waitpid2 pid on each process ID in a global list of all child process IDs across the program).
The second problem was being unable to connect to Sunspot on some of the integration tests that we already had. This one was because of an
at_exit hook that
sunspot-rails-tester had installed that causes the child Sunspot process to be killed once the main process had completed to avoid an orphaned process. My child processes were inheriting this, so that when they completed their task, they were causing the Sunspot process to be killed. This was fixed by creating my own
at_exit hook in the fork block that simply exited with the right status code (which is important), but using
Kernel#exit!, which skips
at_exit hooks, instead of
at_exit hooks are called in the reverse order they are defined. We need our own
at_exit hook because simply calling
#exit! on completion doesn’t account for exceptions.
The final thing I want to mention is that you may want signals sent to your parent process to be propagated to its children processes. This is easy to do: simply call
Process.setpgrp, which “sets the process group ID of the calling process to the process ID of the calling process” (equivalent to
setpgid(0, 0)). Child processes inherit the parent process’ group ID, and any signals sent to a group ID are sent to all members of the group. This effectively means the parent process’ group ID is set to its own process ID, its children inherit the group ID, and so when a signal is sent to the parent process, since the group ID is the same as the process ID, the signal is sent to the group, which is then propagated to all processes in that group (or “session”).
No doubt there’s more that I missed, so please do let us all know if I’ve left something out.
If you’re running a heavy task that can be split up into many independent tasks in a thread-safe manner (I’m assuming you have all those tricky details worked out or you’re willing to work through them), you probably want to parallelise it.
Unfortunately, Matz’ Ruby Implementation has a GIL that prevents more than one thread from executing at a time. It abstracts the OS’ native threads away and uses a scheduling system to make sure that only one Ruby thread is running at a time (with a few exceptions that likely aren’t relevant).
Not to worry, though. Ruby programs can fork themselves to create child processes, and since each Ruby process is independent, you can have as many threads as you like this way.
I knew that there were performance limitations to MRI due to the GIL, but I didn’t realise just how much faster your code could be if you parallelised it. At work recently, I took charge of implementing a new system to handle vehicle images and consolidate all the different ways that we currently process images through our app.
Our users import a huge amount of vehicles through our app every day, and many of those have several images each. We calculated roughly how many images would go through our app every day and it was a large number (~100k at least), but we figured that could be mostly solved using
The real problem was the initial influx of images that we’d have to migrate from a
vehicle_pictures table to the polymorphic
document_assets table that we already have in place for other models. We use Carrierwave.
I did a test run of ~800 images on our QA server and that took ~72 minutes. Evidently not good enough. Using
ruby-prof, I determine that the majority of our time was spent in Carrierwave, in places we couldn’t really do much about. I decided to have a look at parallelising the task and seeing how we could get it down.
My initial implementation got it down to ~20 minutes. Not bad, but then I noticed I had accidentally forked once for each image, as opposed to each batch. Well, damn! Even with all that overhead for each process, the improvement was pretty good. After another attempt, this time creating two processes for each core of the machine (some research online indicated that for IO-intensive tasks like this one, you want at least that much to make sure there’s always one core doing something), yielded ~10 minutes.
The second thing I noticed from the profiling was that a lot of time was being spent in Excon (which Fog, written by the same author, uses, which Carrierwave uses to interface with S3). After benchmarking various Ruby HTTP clients, Excon turned out to be the slowest one by a wide margin. However, I did not deem it worth the work to write our own Carrierwave storage backend given the improvements gained by using the fastest one.
Luckily, our problems were not unique: I discovered a gem called
carrierwave-aws that interfaces directly with
aws-sdk, instead of Fog, and this brought our time down to ~4.5 minutes. I actually managed to get it down to ~2m37s, but retested with only the number of processes I knew we could afford in production, giving us our final ~4.5m figure.
My story is not over yet, though. Automated testing of the multiprocess code has come back to bite me. The previously happy test examples for this class no longer pass, though manual testing shows the same results as before. Parallel code can be tricky to reason about, but it can definitely be worth the payoff.
A couple days ago (on Friday), I gave a talk at work for Dev Forum on (data) types. You can find the Keynote slides here (with presenter notes), and the PDF here (again, with presenter notes).
It’s been a while since my last Dev Forum talk, and I’ve kept meaning to do another one, so although this isn’t the best talk on types (it’s essentially a long introduction to types/a whirlwind tour of different typing systems, as opposed to why types are desirable, their benefits and tradeoffs, etc.), I’m really glad I gave it. I think I had a strong start, too, and I have learnt what to do and what to avoid for next time.
Truth be told, most of the work of actually putting the whole thing together was done on the last day, though the talk had been ruminating for a while now. It’s a recurring theme now, I intend to put my talk together on the second week (Dev Forum is every fortnight), things inevitably end up being really busy, and I skip another week. I had promised to give this talk this week, though, so I couldn’t break that. When I looked back on it later, I even realised I’d completely forgotten a slide on type inference (maybe next time, as I intend to flesh out this topic; it probably fits better in the second presentation, anyway).
Interestingly, I did not feel nervous about the talk until I was actually up on stage (well, metaphorical stage), but I think I managed to hide it pretty well.
After fleshing out this topic, I think I’ll do a talk on fast and efficient typing (well, text editing) ;).
All the links provided in the slides or presenter notes can be found in the list below:
- Free On-Line Dictionary Of Computing, “type”
- Wikipedia article on “Type system”, section on “Fundamentals”
- Free On-Line Dictionary Of Computing, “static typing”
- Free On-Line Dictionary Of Computing, “dynamic typing”
- Wikipedia article on “Latent typing”
- C2 Wiki page on “Strongly Typed”
- Free On-Line Dictionary Of Computing, “strong typing”
- Wikipedia article on “Type system”, section on “Variable levels of type checking”
- Wikipedia article on “Type system”, section on “Optional type systems”
- C2 Wiki page on “Weak And Strong Typing”
- C2 Wiki page on “Strongly Typed Collection”
- C2 Wiki page on “Strongly Typed Without Loopholes”
- C2 Wiki page on “Weakly Typed”
- C2 Wiki page on “Typing Quadrant”
- What to know before debating type systems
- C2 Wiki page on “Soft Typing”
- Wikipedia article on “Type system”, section on “Combining static and dynamic type checking”
- Wikipedia article on “Dependent type”
- The Algebra of Algebraic Data Types, Part 1
- What the Heck are Algebraic Data Types? ( for Programmers )
- Haskell wiki’s “Algebraic data type”
- The algebra (and calculus!) of algebraic data types
- Selected answer to the Programmers SE question, “What Are The Uses of Algebraic Data Types?”
- Wikipedia article on Type system, section on “Static and dynamic type checking in practice”
- Classifying Programming Languages
- An Introduction To Programming Type Systems
- Wikipedia articles on type system and type safety
- Null References: The Billion Dollar Mistake