The Haskell programming language is a lazily evaulated, compiled and interpreted, functional programming language with static type checking and type inference. The type checking and inference algorithm is a modified version of the Hindley-Milner algorithm, which now provides features such as Type Classes, Generalized Algebraic Data Types (GADTs), and Dependent Typing. The Glasgow Haskell Compiler (GHC) is the flagship implementation of Haskell, and is one of the most technologically advanced compilers in wide-spread use today (as of the year 2020).
This is my own implementation of the Collatz function. It uses no packages outside of the vanilla GHC installation, so it can be built simply by running ghc --make collatz.hs
in the command line. Pass the numbers that you want the Collatz function to compute as command line arguments to the program, it will compute the Collatz sequence for each number you give it on a single line of output, for example:
./collatz 31 50 64 77 101
...would output:
31 94 47 142 71 214 107 322 161 484 242 121 364 182 91 274 137 412 206 103 310 155 466 233 700 350 175 526 263 790 395 1186 593 1780 890 445 1336 668 334 167 502 251 754 377 1132 566 283 850 425 1276 638 319 958 479 1438 719 2158 1079 3238 1619 4858 2429 7288 3644 1822 911 2734 1367 4102 2051 6154 3077 9232 4616 2308 1154 577 1732 866 433 1300 650 325 976 488 244 122 61 184 92 46 23 70 35 106 53 160 80 40 20 10 5 16 8 4 2 1 50 25 76 38 19 58 29 88 44 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 64 32 16 8 4 2 1 77 232 116 58 29 88 44 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 101 304 152 76 38 19 58 29 88 44 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
collatz.hs (raw) |
{-# LANGUAGE LambdaCase #-} import Control.Monad ((>=>)) import Data.Function (fix) import System.Environment (getArgs) import System.IO (hPutStrLn, stderr) main :: IO () main = getArgs >>= -- Get command line arguments. (\ case -- Check if there are no arguments. [] -> hPutStrLn stderr "(reading numbers from stdin...)" >> (words >=> lines) <$> getContents -- Read STDIN, break into tokens by whistspace. args -> return (args >>= words) -- Break arguments by whitespace as well. ) >>= mapM_ -- Iterate over input arguments. ( putStrLn . -- Display list on console. unwords . -- Join the list by whitespace. fmap show . -- Convert all integers to base-10 strings. ( fix $ \ loop stack n0 -> -- Begin generating a lazy list. (n0 :: Int) : -- Place the element into the result list. if n0 <= 1 then [] else -- Break the loop if n has converged to zero. if n0 `elem` stack then [] else -- Break the loop if we found a cycle. loop (n0 : stack) $ -- Otherwise, push this element onto the stack and loop. let (n, rem) = divMod n0 2 in -- Check for even or odd. if rem == 0 then n else 3 * n0 + 1 -- The Collatz function. ) [] . -- Initialize the "fix" loop with an empty stack. read -- Parse each input argument. ) |
(Edit: user Opfez notified me of a mistake in the Collatz program I had originally implemented, special thanks to Opfez. This version here is now correct.)
This is just a random thought I have had for a while now: I'd love to write an Emacs Lisp clone in Haskell
Emacs is a Lisp programming environment and app platform that is one of the most generally useful programming tools anyone could possibly ever use. The original Emacs software was first written at MIT back in 1976. It is well known among people in computer-related professions, and has a thriving community of users who contribute their own apps (which are called "Major Modes" and "Minor Modes"). This active community of users, along with a small team of dedicated and highly competent maintainers, keeps Emacs useful even in modern times.
But due to how old the Emacs source code base is, the Lisp interpreter built-in to Emacs is a bit old, and has a bit too much historical baggage. That is not to say that Emacs is a dinosaur. The code base (written in C) is actively maintained and has new feautres added regularly. Functionality for international font rendering, SVG graphics, and JSON parsing and data structure manipulation, are all built-in. Pretty soon, JIT compilation of Emacs Lisp code will be a standard feature, which will make Emacs Lisp code comparable in speed to lanugages like JavaScript.
That said, other aspects of Emacs have made it a bit difficult to modernize. For example, multi-threading in Emacs Lisp is a problem that has proved nearly impossible to solve simply because since the dawn of time the semantics of the programming language have been defined such that the state of the runtime is always mutable everywhere for all functions. This lack of isolation makes it almost impossible to run threads without race condition bugs occuring.
Other problems with Emacs stem from the fact that there is no Document Object Model (DOM), as it was originally an application to run on a teletype terminal (back in the 1970s and early 80s), and only "recently" became a graphics-capable application back in the mid 1990s. So writing graphical apps for Emacs has always been... frustrating to put it mildly.
As a result of issues like this, occasionally people will proclaim that the Emacs Lisp interpreter needs to be rewritten in a newer language like C++, or more recently Rust. But as of today, no successful clone of Emacs Lisp has yet been written. A valiant effort to rewrite Emacs in Guile-Scheme was made back in 2017, but so far the effort has not attracted a large enough base of users, and that code has already bit-rotted.
Well, I am here to make the proclamation yet again: Emacs Lisp needs to be written in a newer language, and Haskell is the correct language in which to implement it. There is an Emacs clone writtin in Haskell as well, called Yi which, like all other clones, only clones the user interface (the key bindings,) and not the Emacs Lisp interpreter. But personally, I believe Haskell would be an ideal language for cloning the Emacs Lisp interpreter core. Haskell has it's own small runtime system (RTS) which it compiles into every binary it builds, and the Haskell RTS has excellent support for automatic garbage collection and multi-threading
The Haskell RTS is considerably smaller than the RTS for other functional programming languages like Steel Bank Common Lisp, althuogh perhaps not quite as small as the RTS for Chez Scheme or Rust. That said, Haskell's high-level language features make it one of the best languages for implementing interpreters and compilers for other programming languages like Emacs Lisp
So that is what I would love to do if I had infinite time and never had to work to earn money, I'd write an Emacs Lisp interpreter in Haskell and port the Emacs app platform over to the Haskell-based lisp interpreter.
=<</ HeMacs \>>= (and :the masters-of :the *hacker-verse*) . ' . . | . - - --^-- - - | ./|\. -- -- | . / \ . | -- -- | ' | | | n | | U | | U | | U | | | U | -- -- | U | | | U | | | U | -- -- | U | | | U | | U | | | U | -- -- | U | | | U | | V | | | | /|\ | ( |<(O)>| ) \\_| \|/ |_// ^^^| |^^^ )///( )///( )///( )///( <|===|> ^\V/^ ^ "By the theory of Lambda, I... have... the POWER!"