HNHacker News
TopNewBestAskShowJobs

TheAsprngHacker

873 karma · joined November 3, 2017

submissionscomments
TheAsprngHacker··on Functor, Applicative, and Monad
The majority of my tutorial actually uses OCaml, though. :P

I like OCaml because it strikes a balance between imperative and functional programming. Maybe learning OCaml would be easier than learning Haskell?

(Plus, OCaml has neat features like polymorphic variants and a powerful module system!)

TheAsprngHacker··on Functor, Applicative, and Monad
To my understanding, although the behaviors of filterM, etc. differ depending on the monad instance, as long as the monad instances follow the laws, those functions like filterM have predictable behavior. It's a consequence of "theorems for free" / parametricity.
TheAsprngHacker··on Functor, Applicative, and Monad
I am the author of this submission. I have strong opinions about functor and monad tutorials, and here are my thoughts:

Back when I didn't understand what a monad was, I would read a bunch of tutorials and get confused by the analogies and examples. For example, I would get confused by comparisons to "boxes," or I would think that Maybe was the definition of a monad, or that IO was the definition of a monad.

The information in the tutorial that you link seems to be all correct. However, it's too "jumpy" for my tastes. The tutorial talks about "contexts," but doesn't really explain what a "context" is, except for making a comparison to "boxes." I get that a functor is an abstract idea, so explaining it in an understandable way is difficult. However, I wish that the article would discuss type constructors, because the idea of mapping types to types is an important part of the definition of functor. Without this explanation, I imagine that the comparison to "boxes" would have given the past me the wrong impression of what a functor is.

In my tutorial, I sought to teach the actual definition of a functor, applicative, and monad. I explain that a functor maps types to types and functions to functions in a way that preserves composition and identity, that an applicative preserves the product, and that a monad is characterized by a "join" operation that "flattens" the data and a "return" operation that "wraps up" the data. I actually would have preferred to explain the actual category theory, but I felt that it would be too intimidating, and so I attempted to convey the ideas in a non-category-theory way. With my current understanding of functor, applicative, and monad, I believe that if one doesn't learn their actual definitions, one doesn't truly understand them. I guess that I wanted my tutorial to be more rigorous.

However, I am not an expert on teaching, so maybe I'm taking the wrong approach.

See my Reddit comment: https://www.reddit.com/r/programming/comments/cy35zz/functor...

TheAsprngHacker··on What Is a Computational Essay? (2017)
See also literate programming, in which the source code is contained inside some kind of prose and the entire file is a valid program: https://en.wikipedia.org/wiki/Literate_programming

It seems that the computational essay is a step higher than ordinary literate programming, as the code is executable in the format being used to present the document.

Reading this submission reminded me of this interactive article on coeffects, which fits the description of a computational essay: http://tomasp.net/coeffects/

TheAsprngHacker··on Summer heat killed nearly 1,500 in France, officials say
I think that the parent commenter was being sarcastic to ridicule people who think that there being one cold winter day means that global warming isn't real.
TheAsprngHacker··on Try Standard ML in the Browser, Courtesy of Univeristy of Saarland
I already submitted this: https://news.ycombinator.com/item?id=20912460

P.S. Are you the same person who submitted this on Reddit?

TheAsprngHacker··on SOSML – Online Standard ML Interpreter
This is the source: https://github.com/SOSML/SOSML

Standard ML (SML) is a typed functional programming language from the ML family (the same family that OCaml is from). SML doesn't seem to receive the same spotlight that OCaml and Haskell do, so it's cool to see an SML project.

Reddit discussion: https://www.reddit.com/r/programming/comments/d1es7v/try_sta...

TheAsprngHacker··on Why Isn't the Intermediate Value Theorem Constructive?
ELI5:

Constructive math is a philosophy of math where you must construct a value to proof its existence. The Intermediate Value Theorem states that if f(a) < 0 and f(b) > 0, then there exists a number c in the interval (a, b) where f(c) = 0. For the IVT to be constructive, you must be able to find c. (Technically, the theorem is Bolzano's theorem, not the IVT.)

The question asks why the Intermediate Value Theorem isn't constructive. The question provides a "binary search" for c.

The answer states that the proof doesn't work because checking whether a real number is 0 is undecidable. A real number is represented by an infinite sequence, and you can't tell if the sequence converges to 0.

TheAsprngHacker··on Functor, Applicative, and Monad
I am the author of this post, please ask me any questions.

Reddit discussion: https://www.reddit.com/r/programming/comments/cy35zz/functor...

My HN submission (which didn't receive any traction): https://news.ycombinator.com/item?id=20850144

TheAsprngHacker··on TypeScript 3.6
I personally don't use Reason. It's syntax is supposed to be more familiar for people coming from JavaScript, but for me, it's weird. My least favorite aspect is the function syntax (both lambdas and function application). Are functions still curried, or...? If they are, then the syntax should reflect that.

As for BuckleScript, I wish that it had better integration with the main OCaml ecosystem. BuckleScript is supposed to work well with NPM, but I am more interested in OPAM. I personally use js_of_ocaml, a compiler to JavaScript that works well with the OCaml tooling.

If Reason and BuckleScript can bring more people to OCaml, then I'm glad. However, I perceive that the people coming to OCaml with BuckleScript seem to be making libraries based around the NPM ecosystem. I feel worried that a separate OCaml ecosystem will come into existence. However, I have not observed any other OCamller voice these thoughts, so I'm probably alone or misinformed here. I'm not too knowledgeable about the JavaScript trends.

Your comment refers to me as an "OCaml person." Please know that these opinions are my own and do not in any way represent the collective OCaml community's opinion on Reason and BuckleScript.

TheAsprngHacker··on TypeScript 3.6
I know OCaml, but not F#.

The most striking difference is that OCaml has the ML module system, where you can have functions from modules to modules. F# doesn't.

Recent versions of OCaml now have features like first-class modules and binding operators. AFAIK F# has not added them.

On the other hand, F# has features that OCaml doesn't, such as computation expressions, strongly typed units of measure, and active patterns.

See https://stackoverflow.com/q/179492/8887578.

TheAsprngHacker··on 33 dead after arson attack at Kyoto Animation studio, dozens injured
KyoAni is responsible for my favorite anime; K-On, as well as Hibike! Euphonium, another anime that moved me. I hope for the best for the families of the dead people, and I hope that the wounded people recover as soon as possible. An attack on KyoAni is an attack on passionate artists following their dreams.
TheAsprngHacker··on Ask HN: Any logic based software dev tool which helps building code gradually?
No, I haven't talked to him about this stuff.
TheAsprngHacker··on Ask HN: Any logic based software dev tool which helps building code gradually?
No, I am not a part of any Slack (or IRC, or Matrix) channels for type theory.
TheAsprngHacker··on Ask HN: Any logic based software dev tool which helps building code gradually?
I can't really answer where I learned this stuff. I got interested in typed functional programming languages and one thing just led to another. I accumulated my knowledge from various places. For example, I first heared about the Curry-Howard correspondence from a page on the Haskell Wiki, but at the time, I had to go to its Wikipedia article to understand it.

I learn type theory from reading on the Internet. My father is a programmer, but he mainly uses C++, so he wouldn't know type theory.

To be honest, I probably wouldn't have learned about type theory if it weren't for the Advanced Topics subculture. My first exposure to programming was with Scratch, and on the Scratch "Advanced Topics" forum (ATs), there is a subculture of people (ATers) who are more knowledgeable about programming than the average user and enjoy pushing Scratch to its limits. (I guess you could say that the ATers are hackers.) One of my friends from the ATs is interested in programming language stuff, and many people there are Lisp hackers. So, the poeple in the ATs are probably responsible for stimulating my curiosity and directing me towards functional programming and PL theory. However, I wouldn't say that I learned type theory from the ATs.

Oh yeah, I also learn type theory from people on the Fediverse (the federated social network that Mastodon uses), as there are people there who are knowleadgable about type theory.

TheAsprngHacker··on Ask HN: Any logic based software dev tool which helps building code gradually?
I am a high-schooler and I understand dependent types. (I am not the person you are replying to, but I am the person who first mentioned typed holes.)

In type theory, there are things called "terms" and "types." A term is something like `fun x -> x`, or `(1, 2)`, or `1 + 1`. In short, a term is basically an expression. Each term has a type. For example, `fun x -> x` might have the type `a -> a` and `(1, 2)` might have type `Nat * Nat`. If a term has a type, it "inhabits" the type. "x has type T" is written `x : T`.

According to an idea called the Curry-Howard correspondence, types can encode logical statements such that terms that inhabit the type are its proofs. Therefore, by inhabiting a type, you are really proving a theorem.

With dependent types, the term and type languages are the same language, so you can mix them together. In short, types are terms.

Here are some types in Martin-Lof type theory:

    ---------
    () : Unit
The unit type is a type with one inhabitant, (). It can be interpreted as the type of the empty tuple. In the Curry-Howard correspondence, the unit type corresponds with truth.

    x : A    y : B
    --------------
    (x, y) : A * B
A * B, the product type of A and B, is the type of pairs. It is based on the Cartesian product operation: https://en.wikipedia.org/wiki/Cartesian_product In the Curry-Howard correspondence, the product type corresponds with logical conjunction (and). By proving A and proving B, you can prove A * B (AKA A /\ B).

    x : Empty
    ----------------
    elim-empty x : a
The empty type is the type with no inhabitants. If you have an inhabitant of the empty type, you can eliminate it to derive anything. The empty type corresponds with falsity, and its elimination means that false implies anything.

    x : A
    --------------
    Inl x : A + B

    x : B
    --------------
    Inr x : A + B
The sum type is the tagged union, meaning "this or that." The type A + B means that the Inl tag holds an A and the Inr tag holds a B. The sum type corresponds with logical disjunction (or).

    f : A -> B    x : A
    -------------------
    f(x) : B
The exponential type, the type of functions, means logical implication. If you have f, a proof that A implies B, and x, a proof of A, you can prove B by doing f(x).

With dependent types, the product and exponential types are generalized into the dependent sum (sigma) and the dependent product (pi) types respectively.

With the dependent sum type, or sigma type `Σ (x : A) B(x)`, the second component in the type is actually a function of A (meaning that B : A -> Type). The dependent sum type generalizes the product type so that the type of the second element of the pair is actually dependent on the first element. In the Curry-Howard correspondence, the sigma type corresponds with existential quantification, "there exists" or "for some." To prove Σ (x : A) B(x), you must inhabit A (show that A exists) and B(x) (where B is a logical statement about x, the inhabitant of A).

With the dependent product type, or pi type `Π (x : A) B(x)`, B is also a function of A that returns a type. The dependent product type generalizes the exponential type so that the codomain of the function, B(x), is dependent on the function's input, x. The dependent product type corresponds with universal quantification, "for all." To prove Π (x : A) B(x), you must prove B(x) for every possible x, where B(x) is a logical statement about x.

Why the dependent product type generalizes the exponential type and the dependent sum type generalizes the product type seems confusing at first glance, but it really isn't:

Σ for x = 1 to n, B(x) = B(1) + B(2) + ... B(n), and if B(x) is some constant C, Σ for x = 1 to n, C = n * C. The same rule applies to types, as multiplication (product) is just repeated addition (dependent sum of a constant).

Π is like Σ, but for repeated multiplication instead of repeated addition. After all, exponentiation is just repeated multiplication.

Another type that you should be aware of is the equality type, `x = y`. In vanilla Martin-Lof type theory, `x = y` is inhabited by `Refl` if `x` and `y` have the same normal form (reduce to the same simplest form). However, there is ongoing research in a field called Homotopy Type Theory, which redefines the equality type in various ways.

Finally, types themselves form a hierarchy. With dependent types, the types themselves are first-class values, and they have their own types. However, `Type : Type` leads to Girard's paradox (similar to Russell's paradox). The solution is for each type to be in a "universe" so that `Type l : Type (l + 1)`, where `l` is the universe level.

Read about Martin-Lof type theory: https://en.wikipedia.org/wiki/Intuitionistic_type_theory

TheAsprngHacker··on Ask HN: Any logic based software dev tool which helps building code gradually?
Your post is very vague, but Agda and Coq use types to help you gradually write definitions. Agda has "typed holes," where you specify the goal type and the IDE (Agda Emacs mode) will show you the relevant bindings in scope. Then, you gradually refine your definition, filling in the hole while creating new holes. Thus, Agda lets you "fill in the blank" using types as a guide. Similarity, Coq has a tactic language that builds terms, and you can see what goals there are left to fulfill and write tactic programs interactively.

Agda and Coq are pure functional languages, and their type systems are a consistent logical system. They are more mathematically oriented and may not be what you want.

Agda Emacs: https://agda.readthedocs.io/en/v2.6.0.1/tools/emacs-mode.htm...

Coq Tactics: https://coq.inria.fr/refman/proof-engine/tactics.html

TheAsprngHacker··on Historically Hollow: The Cries of Populism
I don't think the article is satire. The website seems to be a right-libertarian website, meaning that it promotes laissez-faire capitalism.
TheAsprngHacker··on Snap! 5 is here
Snap! takes inspiration from Scheme. I wouldn't compare Scratch to Lisp/Scheme at all, as IMO lambdas, cons-cells, and (the ability to make) expression-based control structures are all defining features of Lisp/Scheme, and Scratch does not have any of them. To my understanding, Scratch's design seems to be inspired by Kay-style OOP (Scratch's "broadcast" feature is about passing messages between sprites, and the first version of Scratch was written in Squeak).
TheAsprngHacker··on Snap! 5 is here
Scratch lists are not first class. You can only create them as variables; you can't create list "values" (there are no list literals) and you can't pass lists around. You can only provide lists as arguments by choosing list variables from a dropdown of certain built-in blocks.
TheAsprngHacker··on Implement with Types, Not Your Brain
The submission mentions "theorems for free," which answers your question. The a and b type variables can be any type. Because the code has to work for anything, there are not too many operations that you can do on the values of types a or b. For example, if x :: a, you can't do x - 1 because that would require the constraint Num a.
TheAsprngHacker··on OCaml 4.08
I meant Haskell's do-notation sugar - it only works for monads (or applicatives, assuming ApplicativeDo and absence of dependencies on intermediate results). OCaml's new "binding operators" let you define your own variations of `let` and `and`, which resemble do-notation and therefore have the same cognitive convenience. Then, you can define `let` for functors, etc. You can basically have `let` sugar for any operation that takes a function as the second argument.
TheAsprngHacker··on Implement with Types, Not Your Brain
Maybe I'm misunderstanding what you're saying, but how on Earth would a function

    f :: (a -> b -> c) -> b -> a -> c
result in

    f (+) 1 2
evaluating to

    "cookie"
? For one, the types (obviously, to me at least) don't work out.
TheAsprngHacker··on OCaml 4.08
I meant that there being three separate operators makes OCaml's design better than Haskell's. (Of course, this is just my personal opinion.)
TheAsprngHacker··on Luna – A WYSIWYG language for data processing
The Scratch programming language has an unofficial text syntax called Tosh: https://tosh.blob.codes/

The in-development GP language can alternate between blocks and text: https://en.scratch-wiki.info/wiki/GP_(programming_language)

TheAsprngHacker··on OCaml 4.08
This release adds "binding operators," which make functors, applicatives, and monads more convenient to use. The "binding operators" are like OCaml's version of Haskell's do-notation, but IMO even better. In Haskell's do-notation, each binding in the form of `pat <- expr; next` desugars to monadic bind, with an extension to use applicatives instead where possible, but with OCaml's binding operators, there are three separate operators for functors, applicatives, and monads.

The 4.08.0 release also adds the Fun, Option, and Result modules to the standard library.

TheAsprngHacker··on Show HN: "AMD processors sold per year -intel” = snack food
Google seems to assume that AMD means "and." If you put AMD in quotes, the results relate to AMD, at least for me.
TheAsprngHacker··on Ask HN: What do you use linked lists and doubly linked lists for?
Dynamic arrays can be more appropriate than linked lists, depending on the context. Because dynamic arrays multiply the buffer size by a certain factor upon every reallocation, growth of the array is amortized O(1). In addition, dynamic arrays get the benefit of the cache because the elements are contiguous.
TheAsprngHacker··on Ask HN: What do you use linked lists and doubly linked lists for?
Singly linked lists are heavily used in functional programming, and Lisp is famous for them. The reason why singly linked lists are so neat is that they are an inductive datatype that describes a sequence: A list is either empty or an element followed by a list.
TheAsprngHacker··on Why OO Sucks by Joe Armstrong (2000)
I agree with a lot of the criticisms in Dr. Armstrong's article, but I would say that they mainly affect languages such as Java that enforce OO; multi-paradigm languages that allow for OO but don't force it on you don't have these problems. I believe that OOP has valid uses.

> Objection 1. Data structure and functions should not be bound together

In languages like OCaml and C, one defines types separately from functions. Sometimes, however, I find that a function is best associated with a particular type. In OCaml, that's one purpose of modules. (The convention is to call the main type "t.") However, this organization shouldn't be forced on you.

> Objection 2. Everything has to be an object.

This objection only applies to languages like Java that force OO on you. In OCaml or C++, I don't have to use OO, but I still can if I want to.

> Objection 3. In an OOPL data type definitions are spread out all over the place.

Armstrong complains about having to decide what to inherit from when making a Time object. IMO this is a strawman; in Java, classes inherit from Object by default and I don't see any inconvenience. I do agree that it can be annoying that Time has to be object-oriented, and this is where the benefit of OO being voluntary comes in.

> Objection 4. Objects have private state.

I either disagree with or don't understand this objection. Dr. Armstrong lists three ways to deal with state.

His third option is to use pure functional programming. I see both the beauty and practical value in making functions be functions in the math sense, that is to say, mappings from elements of the domain to elements of the codomain. Then, you get equational reasoning. I am sympathetic to this idea. Nevertheless, languages like Haskell aren't for everybody.

His second option is to control access to mutable variables with scope. You can implement a pure function in an imperative way, and that can be a form of encapsulation. This is a good approach, too.

Dr. Armstrong's first option, which he says is the worst, is the idea that objects maintain hidden state which people control via methods. To me, this isn't about state, but rather encapsulation and abstraction. The idea is that when one, say, inserts into a hash table, the person doesn't think about the implementation ("hash the key and walk down the corresponding bucket"), the person thinks of the abstract problem domain ("map this key to this value"). The hash table interface hides its internal state behind the methods. Even in a programming language like C, one writes functions that operate on, and mutate, structs to abstract things away.

Although the second option is good, I see it as orthogonal to the first option, not a superior alternative. If you are going to confine state to within a function, ultimately, don't you have to do mutations on the local variables, and therefore call some kind of method or impure function on them? However, perhaps I am misunderstanding this fourth point.

A lot of arguments, including this submission, pit OOP against FP and argue that FP is superior to OOP. Even though I use FP, I also think that OOP can be useful. They are not opposites and don't have to conflict.

OCaml is infamous for its object layer, yet I ended up using it for a project. I wanted to describe UI "widgets" such that I could compose arbitrary different types of widgets. Before deciding on objects, I had considered first-class modules or a record of functions, but ultimately decided that objects were the most readable choice.

In my OCaml program, I mainly viewed OOP as a way to abstract different types into a common idea. Widgets are all different, and they have different behaviors, but they all have a position in space, a length, and a width. One can also reposition them (mutation!). To me, the purpose of OO is to express ideas such as these. I note that when I used OOP here, I cared less about state and more about the abstraction of what a "widget" was, via dynamic dispatch. It is bad when the language forces OO on you, but it has valid uses.

← PreviousPage 4 of 6Next →