HNHacker News
TopNewBestAskShowJobs

calebh

526 karma · joined December 30, 2010

Senior Member of the Technical Staff at Draper Laboratory in the formal methods group.

Website: https://helbl.ing/

submissionscomments
calebh··on SpaceX just got FCC approval to launch 7,518 satellites
Maybe this will help boost the "game as a service" offerings.
calebh··on Amazon expected to announce NYC and Northern Virginia as new headquarters
Amazon is the new IBM
calebh··on China Telecom diverted internet traffic in U.S. and Canada, report finds
If you read the article closely, it says that traffic was diverted via its PoP on the west coast (presumably in the US). The article isn't saying that there is a cable going out from Canada.
calebh··on The backlash against overtourism
I recently visited Carcassonne, France, and this is how it basically works. The old city is dedicated solely to tourism, and the new city is where all the actual residents live. The old city was abandoned before it was restored, so this situation ended up occurring naturally.

My girlfriend and I stayed at a bead & breakfast in the new city. Most of the tourists are locals from France, but enough people speak English that communication is not a problem.

calebh··on Generating custom photo-realistic faces using AI
Unity has been investing heavily in neural nets for AI. I could envision this also being used for art asset generation. The core TensorFlow API is written in C++, not Python.
calebh··on gRPC-Web is going GA
The gRPC website mentions protocol buffers in the first sentence, and the Wikipedia page says that protocol buffers are used for gRPC. I consider a defacto standard to basically be equivalent to a standard, even if that's not "technically correct".
calebh··on gRPC-Web is going GA
Generics and user defined types make it easier to represent more complicated data. Now everyone is just going to have to write custom encoders and decoders to get the data to a Protobuf compatible format, which is pretty much what we do right now with JSON.

If you haven't used algebraic/sum types before, I highly recommend trying them out. Once you use them you won't want to go back.

calebh··on gRPC-Web is going GA
I think that if we're going to have a full blown typed RPC system, we need to at least be able to represent generics/parametric polymorphism. As far as I know, protobufs do not support this feature! Why are we settling for using a subpar interchange format when the alternative (polymorphic sum types) is so much better?
calebh··on The Many-Worlds Interpretation Has Many Problems
If the MWI is true, then there must be some universes that would experience multiple highly improbable events. These events would be a hint to residents of that universe that the MWI is correct. Why wouldn't the usual Bayesian analysis apply here?
calebh··on The Many-Worlds Interpretation Has Many Problems
Could the anthropic principle taken into conjunction with our continued existence be used to show that the MWI is more probable?

Here's the situation that I'm thinking about: it's well known that we've come close to nuclear annihilation multiple times, either by accident or by tensions between the US and the USSR in the Cold War. If the MWI is correct, it is probable that a good chunk of these worlds have been reduced to ash. However, we currently find ourselves in a world where that has not happened, presumably due to the anthropic principle. Could we then give a numerical probability that MWI is correct, based on this fact?

I'm not a philosopher or physicist - just an interested layman.

calebh··on Haskell's kind system: a primer
In the next version of Juniper everything will be moved over to purely stack based allocation. Currently only function closures and refs are allocated on the heap. The refs are only created once when the program initializes itself, so that isn't an issue. The closures will become part of the function type. The FRP model works very well for the Arduino platform since you're essentially modelling a data-flow from input to output devices. Currently the compilation target is C++, which means that the Juniper compiler doesn't have a ton of control over the final assembly code.
calebh··on Haskell's kind system: a primer
Once you understand kinds, it's not so hard to understand typeclasses and monads. Type classes are a way to overload functions in a controlled way, by defining a set of function signatures where the overall typeclass is parameterized by a type constructor of arbitrary kind. I cover this in my blog post here: http://www.calebh.io/Monads-as-Programmable-Semicolons/
calebh··on Haskell's kind system: a primer
I've worked extensively with functional programming on tiny microcontrollers like the Arduino. I created a research language called Juniper[1], which is a Haskell/F#-like language targeting the Arduino.

As you mentioned, the memory size and the program size are the biggest two constraints. There's no space for a garbage collector, and everything has to be allocated on the stack. It turns out that it is possible to make the entire thing stack-free. The two biggest hurdles are function closures, arrays, and recursive data types.

Function closures are typically allocated on the heap since it's possible to return functions from other functions. The solution is to include the closure as part of the function type, which means that they can then be allocated on the stack. Arrays are a bit more tricky to allocate on the stack. My solution is to statically size arrays with type level natural numbers, which means that the sizes are known at compile time.

Recursive datatypes are a problem that I have not dealt with yet. In most Arduino projects recursive datatypes are not really used, so I just don't allow them. It might be possible to use type level natural numbers to put a bound on recursion depth. Another idea I had was to use run-timed size datatypes. For example, let's say you have a function F1 which calls F2. The frame pointers for their corresponding frames are at S1 and S2. When F2 returns a value of size N, the solution is to copy the value to a scratch space, return to F1, decrement the frame pointer, and then copy the value back into the stack frame. I'm not sure if this is really suitable for embedded systems since it's a lot of code/machinery which takes up precious program space.

Rust is a great language which can work around these issues due to its linear types. I'm looking forward to using Rust once it starts to support the Arduino microcontrollers.

[1]: http://www.juniper-lang.org/

calebh··on Better bus predictions (a lot better)
I use the MBTA buses sometimes to get from my house to the nearest train stop after which I make a transfer to another bus. A real time map of the bus locations would be 100x more valuable than just a prediction.

Same with the train - I use a website that shows the exact locations of all the MBTA trains, and I am able to accurately predict how long the train will sit outside of the Alewife station (which is infuriating BTW) based on the number of trains currently at the platform. A prediction would not be able to take into account this domain knowledge and would be completely worthless.

calebh··on Why Half a Degree of Global Warming Is a Big Deal
News agencies need to stop reporting global warming temperatures in Celsius for US audiences. A single Fahrenheit degree is 5/9 of a Celsius degree! US audiences do not have an intuition about Celsius, so giving changes in that unit of measurement is worthless.
calebh··on Adding an Effect System to OCaml [video]
I'm excited to see that effect handlers are gaining popularity. I read the original papers that introduced them, and I think that they have a lot of potential.
calebh··on Ask HN: Anyone from Google here? The new Gmail UI is painful
Agreed. Why can't software devs just complete a project and then call it good? Perpetual change is unnecessary and a waste of effort.
calebh··on Google Maps won't let you save home address without allowing all Google tracking
Looks like Apple needs to run another 1984 ad during the Superbowl.
calebh··on ITER Tokamak: First Plasma Through High-Fusion-Gain Deuterium-Tritium Operation
What about polywell fusion? Can anyone with expertise comment on this design?
calebh··on Life in the Spanish city that banned cars
People buy cars with their worst case transportation requirement in mind. By moving car ownership to an external fleet, people will be free to only use the extra transportation capacity as needed. Why are we spending all of this energy to accelerate giant metal boxes when most of the trips in cars are only to get a person from point A to point B? It's incredibly inefficient. Self-driving cars and electric bikes are going to completely change the transportation paradigm inside of dense cities.
calebh··on David Patterson Says It’s Time for New Computer Architectures and Languages
It turns out that it is possible to optimally minimize the number of beta reductions in a lambda calculus program. See this excellent blog post: https://medium.com/@maiavictor/some-functions-may-have-negat...
calebh··on David Patterson Says It’s Time for New Computer Architectures and Languages
This sounds good, as a person who specializes in domain specific languages. Maybe we'll see higher demand and corresponding salary increases...
calebh··on China now the most prolific contributor to physical sciences, engineering, math
Hopefully competition from China will spark a re-investment in education elsewhere in the world.
calebh··on Why Rust closures are somewhat hard
C++ closures are a bit weird in that you have to specify how the captured data needs to be captured (either by reference or by copy). How the data is handled also depends on the implementation of std::function (if you decide to wrap your lambdas in that). It's possible that the implementation for std::function actually makes a reference-counted heap allocation every time a new closure is created. Anyway, the result is a lot of complexity that would be impossible to shoe-horn into C.
calebh··on Quaternions: the Strange Numbers That Birthed Modern Algebra
Since other people are giving their monad tutorials, I'll give my take here:

Haskell has a feature called type classes which allows you to overload functions. The definition of a type class gives a list of functions with their type signatures and names. When you write an instance of a type class, you must give implementations for the functions defined in the type class. All the functions that you define in the instance must match the type signature given in the type class definition.

Understand kinds is another critical prerequisite. Have you ever wondered what the type of a type is? Kinds are a simple construction that proves to be useful. Just as expressions have a type signature, a type expression has a kind signature. In its most basic form, a kind tells us how we can construct a type. We represent kinds by using asterisks * and kind functions ->. The asterisk is pronounced as "type".

The easiest way to understand kinds is by looking at a bunch of examples of types and type constructors. Monomorphic types such as Int and Bool have kind * . Type constructors are handled differently. An example of a type constructor is [] (list), which has kind * -> * . So list is a type constructor that takes in a type (which we represent with an asterisk), and returns another type. Therefore [Int] has kind * , since we applied the type Int to the list type constructor [], resulting in the type [Int]. Types constructors can also in some situations be partially applied, just like value constructors. Kinds are right associative, so the kind * -> * -> * is the same as * -> ( * -> * )

Here is a table of some types in Haskell with their kinds:

  +---------------------------------------+-----------------------+
  | Int                                   | *                     |
  +---------------------------------------+-----------------------+
  | Bool                                  | *                     |
  +---------------------------------------+-----------------------+
  | Maybe                                 | * -> *                |
  +---------------------------------------+-----------------------+
  | Either                                | * -> * -> *           |
  +---------------------------------------+-----------------------+
  | [] (list type)                        | * -> *                |
  +---------------------------------------+-----------------------+
  | -> (function type)                    | * -> * -> *           |
  +---------------------------------------+-----------------------+
  | a -> b                                | *                     |
  +---------------------------------------+-----------------------+
  | [Either Int Bool]                     | *                     |
  +---------------------------------------+-----------------------+
  | Either Int                            | * -> *                |
  +---------------------------------------+-----------------------+
  | (->) a                                | * -> *                |
  +---------------------------------------+-----------------------+
  | (,,,) (four element tuple)            | * -> * -> * -> * -> * |
  +---------------------------------------+-----------------------+
  | Mu where                              | ( * -> * ) -> *       |
  | newtype Mu f = In { out :: f (Mu f) } |                       |
  +---------------------------------------+-----------------------+

Now we are ready to look at the type class definition for monad:

  class Monad m where
    (>>=)  :: m a -> (a -> m b) -> m b
    (>>)   :: m a -> m b -> m b
    return :: a -> m a
On the first line, we give the name of the type class: Monad. This type class will be parameterized by a parameter named m. Based on how m is used in the function signatures, we deduce that m must have kind * -> * . This means that when we define an instance of the Monad type class, we tell what m should be. And m can be anything, as long as it has the kind * -> * ! In fact if we look at the table above, we can see that Maybe and the List type constructors have the required kind. If you've read any monad tutorials, these are often used as simple examples of monad instances.

The most important function in the monad type class is >>=, so let's focus on that. >>= is an infix function with two parameters, one of type "m a" and the other of type "a -> m b". The return type of >>= is "m b". So if we were to define a monad instance for m=Maybe, the type of that particular overloaded version of >>= has to be "Maybe a -> (a -> Maybe b) -> Maybe b". What should the definition of >>= be? Well it can be anything as long as the type signatures match up!

Take a look at the second parameter that has type "a -> m b". You can think of this as a sort of callback or continuation function. Typically the >>= function takes the first parameter (which has type "m a"), does some processing to unwrap the value, passes this value to the callback function and then takes this result and does some more processing before returning the result (which must have type "m b"). The >>= can call the callback function as many times as it wants (or maybe not at all). It could do anything, as long as the type signature matches up. There's one more detail that I've so far been ignoring: the overloaded functions need to follow some rules beyond the type signature constraint. These are called the monad laws, and you can find out more about them elsewhere by searching for "monad laws".

Why even bother with the Monad type class at all? It turns out that programmers have discovered many different programming patterns that seem to match up with these signatures. In fact, this particular pattern has become observed to be so common and useful that the authors of Haskell decided to provide some useful built in language operations to make them easier to use (do notation in Haskell). You can think of the >>= as a sort of programmable semicolon, where the overloaded bind operator is parameterized by a specific continuation function, but the overall program flow is dictated by the specific overloaded version of >>=.

calebh··on Quaternions: the Strange Numbers That Birthed Modern Algebra
I've found that the easiest way to understand quaternions is by visualizing them as scaled "look" or "orientation" vectors.

For example, if an airplane is oriented in the direction (x,y,z) at a rotation θ around that axis, then its rotation in quaternion form is cos(θ/2)+x sin(θ/2) i + y sin(θ/2) j + z sin(θ/2) k

Notice that the multiplications involving x, y, and z are just scaling the vector.

The other important thing to realize is that sin(θ/2) is greater than or equal to zero in the interval [0, 2*pi]. So a quaternion is just a look vector where the magnitude of the vector is determined by the rotation around the look vector axis.

See this page for a useful picture: http://www.chrobotics.com/library/understanding-quaternions

calebh··on Current state of the art in objects classification
Agreed. I wish that more effort would be made towards reducing inference time, since that is the limiting factor in many real-world applications.
calebh··on Who owns a scientist’s mind?
Do you have any tips on how to make this happen? When I graduated I felt like I didn't have much leverage on the job offer, but now that I have a couple years of experience I think I can negotiate a better deal.
calebh··on Cheating Fortnite players are flooding the internet with malware
I used to do server development for a very popular free FPS game. At that time the cheat for the game would increase the firing rate of the guns, which I could easily detect. We started slapping on the detection script after some testing, and it started banning tons of people. My conclusion was that the number of cheaters in online games is ridiculously high. We never received any complaints of false positives from players, so I believe that all the bans were legitimate.

Detection is made more difficult by the fact that some players are actually really good. I've been playing Fortnite for only a couple weeks now on the Switch, and I can easily kill ~60% of players. I'm sure that with more practice I could get within the top three pretty consistently.

calebh··on SICP Goodness – Why you don't need looping constructs
C# 4.0 had Linq, which can replace loops in most cases.
← PreviousPage 3 of 5Next →