20 Apr, 2009, David Haley wrote in the 21st comment:
Votes: 0
Lobotomy, what makes you say that Elanthis and I are speaking from conjecture only?
20 Apr, 2009, Silenus wrote in the 22nd comment:
Votes: 0
Elanthis thanks for the answer it helped clarify some points in my mind. I suspect I will have to look into monads a bit more and see what the capabilities and limitations are. Even though I have played around with pure functional languages such as Clean and Haskell I have only done a limited amount of programming in them. Clean was pretty fun to work with but I found the lack of libraries for the project I was working on and the encapsulation issue made modifications to code somewhat difficult (I was doing a Brownian Dynamics simulation).

Quote
Have you ever actually written pure functional code? The reason I ask is that "semantic equivalence" is useless here. Assembler can be written to be "semantically equivalent" to any language … so what?

The reason I keep pushing on this is that the paradigm makes this kind of programming hard. Seriously, just try writing some code with simple data structures with state in a purely functional language, and then compare to a procedural/OO language.

I think you're approaching this whole issue from some very high theoretical level and aren't considering the practical aspects involved. Semantic equivalence is all well and good until you start actually writing code and see how hard it is to achieve that semantic equivalence.


DH I was trying to answer your question rather directly. I.e. you asked if I recall correctly looking a couple posts up whether or not you could implement a list in a pure functional language and use it and the answer is of course yes and I am still not sure what point it is you are trying to make with that example. So what in your mind is useful here? (if semantic equivalence is not?). In many cases manipulating and traversing data structures can be done quite succinctly in pure functional languages with argument pattern matching- but I am sure you know about this. If we discard computational requirements arguably (I am sure you also know this from a previous discussion) it can be more succinct.

Concerning the parallelism point do you disagree with this?
20 Apr, 2009, David Haley wrote in the 23rd comment:
Votes: 0
Actually, I didn't ask whether or not you can implement a list (obviously you can), I just asked how you'd go about doing it, and how you'd go about using it. I'll go ahead and answer my own question at this point. As you know, a "pure function" cannot have side effects. This means that you cannot pass around data structures and manipulate them by modifying their state (for the state change would be a side effect of changing the function). You can of course "modify" a data structure by creating a copy with the desired value updated, but how do you propagate that value to other places that refer to the original copy?

A simple example: consider two actor objects that refer to a third (a group leader). How exactly do you model a state change in that group leader if you cannot effect change upon the objects as side effects?

The terrible consequences of this for stateful applications are why things like monads came about, which as Elanthis said can be basically thought of as delayed state change. But they are not exactly a holy grail solution that makes it completely easy to handle state. (Besides, as he also pointed out, if state change is delayed but inter-dependent, you go back to the same old sequential ordering problem.)

So, the reason I asked you the question was not to see whether or not you can write semantically equivalent code in a purely functional language. The reason was to think about what it would actually mean to write said semantically equivalent code and whether you'd really want to do that.

Frankly, there are reasons why large, stateful applications with inter-object dependencies are not written in purely functional languages. If I had to pick a single reason, it would be exactly this issue of the difficulty of dealing with states.

This is easy to see when you realize that the entire purpose in life of a player's command is to cause side effects.

Silenus said:
Concerning the parallelism point do you disagree with this?

Which parallelism point? If you mean that purely functional languages make it easier to automatically parallelize, I agree with that. If you mean whether or not I think that this implicit parallelism is applicable to a MUD, the answer is no, at least not without a lot of pain that doesn't offset the gain.
20 Apr, 2009, Lobotomy wrote in the 24th comment:
Votes: 0
David Haley said:
Lobotomy, what makes you say that Elanthis and I are speaking from conjecture only?

Well, disregarding that I did not say that, it sounds to me as though there is a lot of speculation going on about how bad of a fit functional programming is for the creation of a mud server with little to no experimentation being done to illustrate/support it directly - that I've heard of, anyways. If someone has attempted this already then I think it'd be something worth hearing about.
20 Apr, 2009, Silenus wrote in the 25th comment:
Votes: 0
I might be misunderstanding something here but isnt that in some sense approaching the problem from the wrong direction in the pure functional style? i.e. arent you from my rather newbie point of view suppose to pass in the state and pass it back out? I.e. per your two actors example I suspect the correct way to do this would be to pass the state into and out of the functions in question. The problem is as I said a matter of encapsulation since you have dataflowing through functions which may not use them at all.

This point-

Quote
Quote
Well, in a pure functional language, it's not hard at all to parallelize computation. The hard part is deciding what might be worth parallelizing (i.e. when the overhead is offset by the gain). Remember that in a pure functional language nothing has side effects, so any computations can be done in parallel as long as their inputs have been calculated; ordering the computations is pretty easy to do.


Isnt this precisely the problem though? most functional computations are described in terms of recursions (for example in lisp this would be recursions in most cases over lists) so the call graph and thus inputs are severely constrained a priori- so unless you do some restructuring you cannot make progress in alot of cases. Even something like map/apply over a list is typically described as a simple list traversal recursion when in fact it can be data parallel.


Though in principle they are easier to parallelize it is still a hard problem because of having to mutate the call graph to get parallelism out of it.

I guess maybe I shouldnt try using this compiler for mud development (i.e. as a basis of an engine) :/.
20 Apr, 2009, Lobotomy wrote in the 26th comment:
Votes: 0
Silenus said:
I guess maybe I shouldnt try using this compiler for mud development (i.e. as a basis of an engine) :/.

20 Apr, 2009, David Haley wrote in the 27th comment:
Votes: 0
Lobotomy said:
Well, disregarding that I did not say that, it sounds to me as though there is a lot of speculation going on about how bad of a fit functional programming is for the creation of a mud server with little to no experimentation being done to illustrate/support it directly - that I've heard of, anyways. If someone has attempted this already then I think it'd be something worth hearing about.

Of course you said it, and you just said it again, although I will grant that this time you were a little more direct about it. :wink:

Anyhow, I still don't know what basis you have for thinking that this is just speculation on our end. Even if it were, I don't know why you believe that something has to be tested before you assign high likelihood to it. I know that using a saw to put in nails is not going to work very well, even though I haven't actually tried it. I just understand the nature of the tool and the problem well enough to know that it's not the right solution. (Yay for utility tool metaphors ad nauseam)
But really, knock yourself out if you care to experiment. It's a good learning experience to understand how these paradigms work if the arguments up until now haven't floated your boat.

Silenus said:
I might be misunderstanding something here but isnt that in some sense approaching the problem from the wrong direction in the pure functional style? i.e. arent you from my rather newbie point of view suppose to pass in the state and pass it back out?

Well, sure. But when the "state" is basically the whole program (because of how utterly interrelated things are) you would probably start wondering if this is a good idea.

Silenus said:
Though in principle they are easier to parallelize it is still a hard problem because of having to mutate the call graph to get parallelism out of it.

Oh. Well, not really, in many cases. Without expecting the compiler to be incredibly clever, you can parallelize an awful lot very easily (ignoring the question for now of whether you should). For instance, map operations, list comprehensions, etc. can all be recognized immediately from use of built-in functions or syntax. Languages like Erlang make automatic parallelization easy due to the structure and restrictions of how you write things.

Another easy opportunity for parallelism is the combination of expression results:
return f(a) + g(b) + h©
since functions are pure, you can parallelize all three computations without worrying about what goes on inside.

I think the hard question here is really when you should parallelize. In the above example, if f, g and h are very cheap, you'd most likely end up hurting yourself with the overhead involved in parallelization.
20 Apr, 2009, Silenus wrote in the 28th comment:
Votes: 0
Well my target has always been to build an engine not a mud specifically in this case hence all the questions. The parallelism thing is a side issue for me though interesting. I am aware of the encapsulation problem it's why for the simulation I was writing I decided to migrate to C++. It was an interesting exercise to do in an pure functional language but having to pass data through to alot of different places in the system caused alot of maintenance problems when I was trying to modify the program. The lack of libraries as posed problems for me w.r.t Clean. I think proposals exist which may or may not be implemented in GHC to cope with some of these problems so perhaps I might need to experiment with those if I still want to do muds with this compiler project.

As for the point w.r.t. builtins and special syntax. I am aware that you can in principle use builtins and make things data parallel(ignoring for the moment if it's cost effective to do so) but this doesnt help with alot of situations where someone might want to implement operations which traverse a recursively defined type. I probably should take some time and look at the cost models. The target I assume is usually you go for outer loops to offset the potential overhead with parallel code. I guess I may have to look at the Erlang source code and see if they do any automatic parallel stuff.

Thanks for the replies everyone.
20 Apr, 2009, David Haley wrote in the 29th comment:
Votes: 0
Silenus said:
but this doesnt help with alot of situations where someone might want to implement operations which traverse a recursively defined type.

If you're referring to the conversation we were having on IMC a while ago, I would note that in practice the majority of traversals follow pretty clear patterns. For the purpose of a mapping algorithm for instance, it doesn't matter how the structure is defined as long as you can iterate over it with a known interface. Just iterate over it, and parallelize each application of the mapping function. So like I said, there are lots of very simple ways to address this part of the problem. The question of whether something would actually benefit from being run in parallel is quite different.
20 Apr, 2009, Silenus wrote in the 30th comment:
Votes: 0
Well I think the difficulties start coming about when you have to traverse a pair of data structures and my understanding is that you have to define custom traversals for this purpose. I.e. in a "point-free" style to implement zip() my limited understanding is that you have to define it in terms of an unfold instead of a fold function and to define this kind of construct you have to specify things in terms of a traversal pattern. The problem is given these definitions are in a pure functional style you would have to convert recursions into iterations. I guess in some cases this isn't too difficult since the functions are tail recursive and these can be converted into iterations quite cleanly.

However even for something as simple as a Fibonacci recurrence this might not be so obvious. There are methods for handling these sorts of cases though I am not certain if they have yet been implemented into any compiler and I am not sure how mature they are, what kind of coverage you get and how often these cases come up in real programs.
20 Apr, 2009, David Haley wrote in the 31st comment:
Votes: 0
Well, all I can say is that in practice, many (or even most) data structure traversals aren't terribly esoteric. I think you're "over-solving" this, to be honest. If the question is what the (dis)advantages of functional programming are, esp. as far as MUD programming is concerned, one can talk about that without getting into mathematical theory, advanced compiler design and so forth.
21 Apr, 2009, Silenus wrote in the 32nd comment:
Votes: 0
Yep. It's pretty much as I expected- I actually posed the question because I was wondering if I was wrong about pure functional programming and the inherent difficulties in applying it to muds. Most of the arguments presented are actually quite similar (though perhaps more nuanced) to my internal dialogue on the subject. I have been mostly of the mindset how can this be made to work without going into tremendous contortions. I.e. had I inherently missed something in my analysis.

I guess if I want to do this I will have to split my project in two pieces one which version which is not pure ala ML/Lisp and another which is.

I guess I am also looking at it from a compiler design/mathematical standpoint because simply that just happens to be what I am working on.
01 Jun, 2009, ekiru wrote in the 33rd comment:
Votes: 0
You all seem to be equating functional programming with purely functional programming with no side effects whatsoever. Even Haskell programmers wouldn't try to implement a MUD that way. They would implement it in a functional manner, though. For a MUD, they'd probably have to rely heavily on IO, but some of the other characteristics of functional languages(list comprehensions, higher order functions, anonymous functions, etc.) can be very useful, and implementing what parts of your MUD that can be implemented in a purely functional manner can make your code easier to understand and as a result easier to maintain and change.

I probably wouldn't write a MUD in Haskell(I don't like static typing), but if I write a MUD, I'll probably write it in a functional language(possibly Erlang or a Lisp(either Clojure or mzscheme, most likely(CL doesn't have tail recursion and Arc hasn't developed enough for pg/rtm to bother with efficiency yet(nor has a standard module/namespace system been developed for it)) (My fondness for Lisp is probably noticeable))) because Erlang is a perfect language for a MUD server, and even if Lisp were less suited than a more imperative- or OO-focused language for the task(which I don't think is the case, especially with the advantages of first-class functions(often first-class-continuations as well), tail-recursion(except in common lisp, unfortunately), lexical closures, lambda/fn, etc.), with Lisp, especially with macros, I'd be able to write it much faster. If one wanted to, one could probably write a library of lisp macros to write the necessary java/c/c++/python to write a MUD then write a MUD with the macro library faster than Ionecould write one in Java, C, C++, or maybe even Python.

There's no reason to split languages to write a non-entirely-purely functional MUD server. You can write the impure code in Lisp just as easy as in an imperative language.
01 Jun, 2009, David Haley wrote in the 34th comment:
Votes: 0
ekiru said:
(CL doesn't have tail recursion and Arc hasn't developed enough for pg/rtm to bother with efficiency yet(nor has a standard module/namespace system been developed for it)) (My fondness for Lisp is probably noticeable)))

The nested parentheticals kind of gave that last bit away… :tongue:

ekiru said:
If one wanted to, one could probably write a library of lisp macros to write the necessary java/c/c++/python to write a MUD then write a MUD with the macro library faster than Ionecould write one in Java, C, C++, or maybe even Python.

That'd be a neat trick, although I admit that I'll believe it when I see it. This is the kind of claim that's made a lot but never actually put to the test, at least in my experience.



As to the rest:
We were talking about pure functional languages because that is what the OP was interested in. I fully agree that there's no need to equate "functional" with "purely functional", and yes, the high-level constructs are extremely useful for making the code more understandable. Incidentally, "purely functional" routines in C/C++/other languages are also helpful for understanding and enforced documentation of intent, and one reason why I always say that using 'const' whenever possible is beneficial.
01 Jun, 2009, ekiru wrote in the 35th comment:
Votes: 0
David Haley said:
That'd be a neat trick, although I admit that I'll believe it when I see it. This is the kind of claim that's made a lot but never actually put to the test, at least in my experience.

Part of the reason it's never(or at least rarely) put to the test is that laziness is a good quality in programmers, and it's easier to write what you need in lisp. I know the reason why I don't do that is laziness. :grinning:

David Haley said:
As to the rest:
We were talking about pure functional languages because that is what the OP was interested in. I fully agree that there's no need to equate "functional" with "purely functional", and yes, the high-level constructs are extremely useful for making the code more understandable. Incidentally, "purely functional" routines in C/C++/other languages are also helpful for understanding and enforced documentation of intent, and one reason why I always say that using 'const' whenever possible is beneficial.


Silenus seemed to be dismissing functional languages as a whole simply because purely functional code would be too awkward for a MUD server, and I thought I should point out that it's not necessary to dip into a more imperative language for the stateful aspects of your code. After all, operating systems are about as stateful as you can get, and writing the OS purely in Lisp worked out well enough for Lisp Machines in their day. Erlang's also a very intriguing option, and it's rather well proven how effective it can be for developing complex systems which scale ridiculously well(although a MUD really requiring its power seems unlikely).
02 Jun, 2009, Tyche wrote in the 36th comment:
Votes: 0
I haven't been able to find a Lisp mud, although I recall dozens of vaporware projects over the years.
There are several muds that implement Lisp as an embedded language, DUMB and MUQ, for instance.
I don't know why nobody ever seems to release a finished project.
02 Jun, 2009, David Haley wrote in the 37th comment:
Votes: 0
Some programmers are more interested in talking about the great things that can be done with their language to end all languages than solving the nitty gritty details of actually writing a complete product. :tongue: More seriously though, when people are more interested in showing off nifty high-level features, they tend to get discouraged when they realize that they can't do so without implementing a bunch of low-level handling for relatively less interesting aspects of a program like this.
02 Jun, 2009, Tyche wrote in the 38th comment:
Votes: 0
David Haley said:
Some programmers are more interested in talking about the great things that can be done with their language to end all languages than solving the nitty gritty details of actually writing a complete product. :tongue: More seriously though, when people are more interested in showing off nifty high-level features, they tend to get discouraged when they realize that they can't do so without implementing a bunch of low-level handling for relatively less interesting aspects of a program like this.


Oh there's no shortage of "functional" (pun intended) muds written in almost any language. I just couldn't find any outside the embryonic stage for Lisp, Guile, Scheme, Haskell, etc. The closest I found to a working implementation is scheme-mud written in Scheme which hasn't made a release but it looks pretty darn close and very recent ( http://github.com/andrew-wja/scheme-mud/... ).
02 Jun, 2009, Runter wrote in the 39th comment:
Votes: 0
[long winded promotion of Ruby]
03 Jun, 2009, Tyche wrote in the 40th comment:
Votes: 0
Runter said:
[long winded promotion of Ruby]


Ruby is the best…
Mr. Spock on Ruby… http://www.youtube.com/watch?v=Tk57tQmRw...
Walter Brennan… http://www.youtube.com/watch?v=e7kRO6Iov...
Kenny Rogers… http://www.youtube.com/watch?v=_ZYcqlEZx...
The Killers.. http://www.youtube.com/watch?v=TtyeCSIyv...
20.0/51