HN user

porges

196 karma

[ my public key: https://keybase.io/porges; my proof: https://keybase.io/porges/sigs/SrCe3riFOwxMh1cQghPWntrfxUIQUx_rm_xHfyhZmiM ]

Posts0
Comments74
View on HN
No posts found.
2D Syntax 9 years ago

At that point aren't you just doing normal Racket pattern matching?

    (match
      (list (> x y) (stringp foo) (oddp n))
      [(list #t     _             #t      ) (whatever)]
      [(list _      #t            _       ) (other-thing)]
      [(list #t     #f            _       ) (etc)])
... or is that the joke :)
Me and SVG 9 years ago

This looks really good, thanks! Nice support for isometry.

Paxos in 25 Lines 9 years ago

("Free-format") Fortran has a max line length of 132 chars, up from ("fixed-format") 72 chars on punch cards.

FYI: `languæge` and `charæcters` don’t make much sense—‘æ’ and ‘œ’ usually changed to simple ‘e’ in modern English (Encyclopædia, mediæval), unless at the start of a word (æsthetics). There are variations, ‘œ’ seems to have been more likely to change to ‘e’ at the start of a word (œsophagus, œstrus).

Also, not every ‘ae’ was an ‘æ’—‘aerial’ is one example. I think the test is whether or not the Greek word used ‘αι’.

After instructions, participants were given printouts of sample code they could refer to while solving tasks. Group Lambda got code of a C++ program using lambda expressions and group Iterator received code of the same program written using iterators. They then had time to study the samples before starting the tasks and could refer to these samples later.

These samples do not appear in the paper, so we don't know what they saw.

The “iterators” discussed are Java-/C#-style iterators, not C++ ones (as I expected reading the abstract).

In a C++ context I would have expected lambdas vs iterators to be something like:

    // lambda
    float retVal = 0;
    std::for_each(mb.cbegin(), mb.cend(), [&](item x) { retVal += item.price; });
    return retVal;

    // pure iterator
    float retVal = 0;
    for (auto it = mb.cbegin(); it != mb.cend(); ++it)
    {
        retVal += it->price;
    }

    return retVal;
... and the first would be better off as:
    return std::accumulate(mb.cbegin(), mb.cend(), 0f,
        [](float acc, item x) { return acc + x.price; });

I think the need to use ref-capture (since you only get a side-effecting `std::function` to play with in their sample) would be the thing most likely to throw people off – as it’s something that should be avoided in most code, anyway ;)

The Tài Xuán Jīng symbols are, however. A subset can be used like:

𝌆𝌇𝌉𝌊𝌏𝌐𝌒𝌓𝌡𝌢𝌤𝌥𝌪𝌫𝌭𝌮

So Unicode has Bagua (3 bits), Tài Xuán Jīng (4 trits), and I Ching (6 bits, but incomplete).

Something does seem funky. The website looked like this in 1997: http://web.archive.org/web/19970418234503id_/http://www.bath... [This page is 3,780 bytes.]

In fact, you can find the server stats from back then: http://web.archive.org/web/19970822145424/http://www.bath.ac...

This says that it transferred "3 599 Mbytes" and there were "728 506" requests. Interpreting "3 599" as 3.599 gives 4.94 bytes per request, which is absurd. It must be 3.6 GB, making each response just under 5 kB. This seems much more reasonable.

So the number on that page should probably be interpreted as 63 GB, which is reasonable if we assume the site became more popular later in the year, as the original source suggests (3.6 GB*12 = 43.2 GB, and the stats are from May).

Also notice the following year (1998) says 126 MBytes and in 1999, 197 GB. That's an order of magnitude jump!

These exist in Haskell as "Pattern Synonyms". Here's a partial translation of some of the F# examples on MSDN to Haskell;

  {-# LANGUAGE PatternSynonyms, ViewPatterns #-}

  pattern Even <- ((`mod` 2) -> 0)
  pattern Odd <- ((`mod` 2) -> 1)

  testNumber x = show x ++
      case x of
          Even -> " is even"
          Odd -> " is odd"


  data Color = Color { r :: Int, g :: Int, b :: Int }

  pattern RGB r g b = Color r g b
  -- NB: this is bidirectional automatically

  printRGB :: Color -> IO ()
  printRGB (RGB r g b) = print $ "Red: " ++ show r ++ " Green: " ++ show g ++ " Blue: " ++ show b

  -- pretend we have functions to and from RGB and HSV representation

  toHSV :: Color -> (Int, Int, Int)
  toHSV = undefined -- implement this yourself!

  fromHSV :: Int -> Int -> Int -> Color
  fromHSV = undefined

  pattern HSV h' s' v' <- (toHSV -> (h', s', v'))
      -- here we explicitly provide an inversion
      where HSV = fromHSV

  printHSV :: Color -> IO ()
  printHSV (HSV h s v) = print $ "Hue: " ++ show h ++ " Saturation: " ++ show s ++ " Value: " ++ show v

  -- demonstrating being able to use pattern
  -- to construct a value
  addHue :: Int -> Color -> Color
  addHue n (HSV h s v) = HSV (h + n) s v

The point here is not particularly about signedness, it's that UB allows better optimizations to be performed.

If overflow is defined to wrap around then it's potentially an infinite loop (take N == MAXVALUE). With overflow defined as UB you can say the loop executes exactly N times (because you're not allowed to write code that overflows).

So UB is both bad and a source of power :)

It seems the terrible performance of the STL can be explained by std::string: this thing hits the general purpose allocator every time a new string is constructed. In this benchmark, that means every time we insert a string, possibly more. Not good for such an inner loop. There are ways to speed things up, but that would complicate the code, and defeat the purpose of leaning on the standard library.

It's actually reasonably easy to avoid the unnecessary copying.

Something like this would do (use a string as the buffer, pass it by reference, then use `try_emplace`). Also, it should probably be using the same hash function as your C code:

    #include <cstdint>
    #include <fstream>
    #include <string>
    #include <unordered_map>

    class Intern_pool
    {
        struct fvn_hash
        {
            // FVN-1a hash -- http://isthe.com/chongo/tech/comp/fnv/
            std::size_t operator()(const std::string& s) const
            {
                std::size_t hash = 2166136261; // offset basis (32 bits)
                for (auto c : s)
                {
                    hash ^= c;       // xor
                    hash *= 16777619;   // prime (32 bits)
                }
                
                return hash;
            }
        };

        std::unordered_map<std::string, std::uint32_t, fvn_hash> map;
        std::uint32_t next = 0;

    public:
        std::uint32_t add(const std::string& s)
        {
            auto r = map.try_emplace(s, next);
            if (r.second)
            {
                ++next;
            }

            return r.first->second;
        }
    };

    int main(int argc, const char* argv[])
    {
        for (int i = 1; i < argc; ++i)
        {
            std::ifstream file(argv[i]);

            Intern_pool intern_pool;

            std::string line;
            while (std::getline(file, line))
            {
                intern_pool.add(line);
            }
        }

        return 0;
    }

Each element of your matrix doesn't really have its own type, each column and row has a type:

                            1
                          +---
                       V  | V
                      Pa  | Pa

          V^-1    Pa^-1   
         +--------------- +-----
    mA   | mA/V   mA/Pa   | mA
    kg/s | kg/V/s kg/Pa/s | kg/s
I can imagine a system that types this quite well.