HN user

RootDynasty

22 karma
Posts0
Comments9
View on HN
No posts found.

In my opinion the most important part of functional programming is the purity of functions. There is a great quote about this on one of the Clojure doc pages

"If a tree falls in the woods, does it make a sound? If a pure function mutates some local data in order to produce an immutable return value, is that ok?"

Function purity enforces that mutations are localized to small areas of the code, while maintaining composition.

The language part of the Wolfram Language is still really kludgy to use and quite slow. Even doing simple things like writing a function or an if statement is painful. What it does have going for it is the biggest, baddest standard library available.

imo, the language would be much more compelling if the syntax was redesigned from the ground up and made easier to debug (the error messages in Mathematica are next to useless)

Does Atomontage have support for real time shadows? All of that information seems to be pre-baked into the voxel models. This would severely limits its "everything is destructible" potential. It should be able to support some screen spaced based effects such as deferred shading and SSAO at least.

I agree that worrying about the time complexity of the non-parallel portions of pmap is unlikely to be an issue for most use cases. It's still interesting to think about the tradeoffs though.

Hitting the degenerate case depends on the function you're computing in question. It's quite possible that the tasks will complete in the given order. I think you're giving too much credit to Erlang's task scheduler.

Also I'm not sure how one would even implement a tail recursive map function on a singly linked list. The cons operation can only add elements to the front of the list. I looked up how the map operation is implemented in Erlang. It isn't tail recursive:

https://github.com/erlang/otp/blob/172e812c491680fbb175f56f7...

I'm interested to know how you'd implement a tail-recursive version of map (continuations aren't allowed).

One thing to note is that the the parallel map consisting of two mapping operations has a different hidden overhead. If a message is received by a process that does not pattern match with any clauses in the receive block, the message is stored in a queue. When a new receive block is entered, all messages in the queue are pattern matched against the new receive block. In the worst case scenario, the worker process mapping the elements will finish in list order, so a great many pattern matches will be tried.

The solution to this problem is just to store messages as they are received inside of a map data structure, so that there is no overhead for receives. This requires indexing the list which makes the code a lot more inelegant.

Edit: Given n processors and an input of size n, I believe the time complexities are: Two map solution: O(n^2)+O(f) Fold solution: O(n^2)+O(f) Two map with map data structure: O(n)+O(f)

Where O(f) is the asymptotic upper bound of the function being mapped

Edit 2: This has me thinking about what will be the most efficient way to assign an element from the list to worker processes. In Erlang, it's clear that there isn't a way to avoid the O(n) overhead since the original process must reconstruct the list in order using cons.

In an imperative language this isn't necessary. Perhaps the original process can recursively assign indicies by spawning two children worker processes which are given a range of indicies to work on (who then create their own assignment processes). I believe the overhead is then only O(log n)...

Here is another cool version of parallel map in Erlang that uses a fold instead of two parallel maps.

  parallel_map(Fun, List) ->
      Last = lists:foldl(fun(Value, Parent) ->
          spawn(fun() ->
              MappedValue = Fun(Value),
              receive
                  Rest -> Parent ! [MappedValue|Rest]
              end
          end)
      end, self(), List),
      Last ! [],
      receive
          Result -> Result
      end.
It essentially sets up a chain of processes which pass their results to their parent when they finish their mapping operation.
2048 in Erlang 12 years ago

Is using relx in conjunction with rebar a standard thing to do? Is there an easier/standard way to start the app with rebar or relx in development without building an entire release? Having to manually call ensure_all_started while developing seems a bit strange to me.