Are there any 100% pure languages (as I describe in the Stack Overflow post) out there already and if so, could they feasibly be used to actually do stuff? i.e. do they have an implementation? I'm not looking for raw maths on paper/Pure lambda calculus. However Pure lambda calculus with a compiler or a runtime system attached is something I'd be interested in hearing about.
-
2TL;DR. btw when a question get's closed on StackOverflow, it will probably get closed here. If it did fit Programmers, it would get migrated here instead.– yannisNov 22, 2011 at 8:54
-
6To get an answer you might want to shorten down the context description to a minimum (now it looks like a blog post) and leave the last paragraph. You could also link to a discussion somewhere else.– l0b0Nov 22, 2011 at 9:00
-
3@ThelronKnuckle, insulting the people of whom you're asking a question probably won't invite a warm reception. It's not about poor attention spans. It's about writing a question that doesn't waste the reader's time. Condense your question to its essence.– Frank SheararNov 22, 2011 at 9:26
-
1@TheIronKnuckle I spend an hour writing a compiler in javascript, its lying around on a jsfiddle somewhere, seriously write one yourself, it's trivial. Other then that just use this one– RaynosNov 22, 2011 at 10:44
-
4A language which doesn't let you do IO is a completely useless language. Programs written in such a language can do calculations, but they can't report the result of the calculations to you... the only way you can tell that it's doing anything at all is that your computer gets hot!– Benjamin HodgsonMar 3, 2014 at 0:10
6 Answers
Indeed, as Simon Peyton Jones once stated, Haskell is the finest imperative language out there.
Seriously, purity is not a religious issue. The problem is not that impure functions and mutable data exist. The problems in conventional languages is that often you can't tell impure frm pure and mutable from immutable: not by looking at it, not by compiling it, only by running it.
This is the great advantage that Clean, Haskell (and followers like Frege) have. Conversely, languages like F#, Scala or Clojure that embrace the imperative world and just add the possibility to build something functional alongside suffer from the same problems as the imperative languages, although they may seem very practical indeed.
-
-
Another worthwhile perspective - Monads in Haskell get some syntactic sugar, but the basic construct is just a kind of abstract algebra - Monads can be (and have been) used in other languages including Objective CAML and even Javascript IIRC. So arguably, no language can be purely functional - the functional building blocks allow imperative programming (in monadic form) to be provided as a library.– user8709Nov 22, 2011 at 10:49
-
But when you dig into it there's no implicit state or side-effects in the monads, so what looks like impure code is deceptively pure :P Hell, with continuations you can get even get purified goto (in a sense); Nov 22, 2011 at 11:32
-
1I am working on a short e-book on JavaScript Monads for O'Reilly, it should be out early next year. Nov 22, 2011 at 14:05
-
even C++ compilers have mechanism available to compile-time check for side effects. (hint, it's const) But normally that's not enough, since an elephant can run through the stuff that doesn't do the check.– tp1Nov 22, 2011 at 16:51
It seems to me you're trying to reinvent Haskell.
The language doesn't need to have side effects at all. The run-time system does. The compiler/run-time system simply needs to search for the main function and treat it as an entry-point to the program as a whole.
Nice description of how IO is done in Haskell.
Hell, maybe you could execute until you need to prompt the user, wrap up the remainder of the code as a completely new program in the return type
You mean monads?
>>= :: M a -> (a -> M b)
After the first half (M a) prompted the user to provide data (of type a), the second half (a -> M b) is the the "remainder" you describe.
If Haskell allowed you to introspect functions instead of just allowing you to run them, it would also be homoiconic.
-
"It seems to me you're trying to reinvent Haskell." Haha, I've been slowly realising that over the past 6 or so hours. Should I be proud or slap myself for proposing to reinvent the wheel? :P Nov 22, 2011 at 12:51
-
1@TheIronKnuckle do both. I'll leave the order of 'evaluation' to you :)– OlumideJul 12, 2016 at 14:18
I would regard Haskell as 100% pure. And it can certainly get stuff done.
While there are some good debates about what "100% pure" actually means, it is certainly not true that a pure functional language cannot do IO. See also the comp.lang.functional FAQ.
All you have to do to allow IO in a pure language is pass a parameter that represents the state of the world to the program, and return the state of the world as an output. This program has no side effects, is referentially transparent and counts as 100% pure. This is pretty much what Haskell's IO Monad does under the hood.
A special mention perhaps for Clojure, which is definitely a practical language with the entire JVM ecosystem and toolchain to your fingertips. It is clearly not 100% pure (since you can get side effects via the STM managed references, various IO functions or Java interop). However the core language if you avoid these special cases is purely functional. So if you stick to the pure subset of Clojure, you actually have a pretty decent pure functional language for most purposes.
-
1Re: "This program has no side effects, is referentially transparent and counts as 100% pure", this only holds if we ascribe a whole lot of extra meaning to the
RealWorld#
baton passed between IO actions. In reality, it's just a token, so it is not a ticket to referential transparency of IO actions. The argument gets even weaker in the presence of threads, since now each thread has aRealWorld#
, and who's to decide which one is "accurate"?– AdamNov 22, 2011 at 15:10
A "pure" language that couldn't do IO couldn't do much. ...after all, even printing a result on the screen is IO. So if you can't see the result of a program, wouldn't it be rather pointless?
You couldn't read files, couldn't listen to sockets, couldn't interact with users, couldn't ask for input... etc. What good would that be?
That said, Haskell is the closest to "pure" (whatever that means) functional programming I know of. Their whole IO system is even made using Monads, which kind of a mix between IO and functional.
I also know of "Clean" which is an academic functional language and sees IO as a transform of a World object if I remember right ...however, this starts to be very exotic.
-
-1 because pure does not mean "no IO". Pure functional langauges like Haskell can do IO - one way of doing this is by passing a parameter that represents the state of the world to a function that represents a "task". See Haskell's IO monad for example.....– mikeraNov 22, 2011 at 10:11
-
@mikera - but even SBC (who was at least a main designer of Haskell and also one of the implementers of GHC) recognises monadic code as impurity. Controlled impurity, with side-effecting code marked out explicitly and a clean separation of side-effecting and non-side-effecting code, but still impure. Basically, Monads show that impurity can be created from pure ingredients.– user8709Nov 22, 2011 at 10:53
-
@Steve314 I think it comes down to definitions :-) If you take pure to mean "referentially transparent/no side effects" then you can never built impure functions with pure functions. If you take impure to mean "in an imperative style" then I certainly agree that you can use monads to construct something that behaves in an imperative fashion.– mikeraNov 22, 2011 at 11:23
-
2tbh I don't see monads as having much to do with it at all. The IO monad is not special, it's just a way of dealing with the IO that is happening somewhere completely different. Outside the scope of the language + program. I've never tried, but I'm guessing you can still run a haskell program and turn off the side effects in the run time system; you don't have to change your code at all. All those dasterdly monads will remain. The end result will be a pure IO action that never did anything. This shows how side effects happen outside the language. Monads just help to control them Nov 22, 2011 at 11:30
-
@mikera - I don't think my previous comments were clear, so I'll try another approach. When a politician is less than transparent, a common approach is to bury the relevant in a mass of the irrelevant. Giving an explicit name to the entire mass of relevant and irrelevant doesn't remove the referential opaqueness. And this does happen in functional programming - a value passed to a function is quite often a mass of irrelevance along with a few relevant details. Passing "the world" to a function when only a few aspects of the world are relevant is an obvious example of referential opaqueness.– user8709Nov 22, 2011 at 12:24
"Purely functional language" is a quite confusing term. Taken literally, the term means something like "a language that is only functional and nothing else". So it encompasses Haskell, ML, Clean, etc.; Scheme comes close but doesn't quite make it; and the "impure" functional languages are strictly Perl, Scala, JavaScript, etc. --- "multi-paradigm" languages with good support for functional programming. That's clearly not what people mean by "purely functional", though.
The key is to understand that people who say "purely functional language" really mean to say "pure functional language" --- a language based on pure functions --- and "purely functional" is a slip of the tongue that's become conventional. The motto is "it's the functions that are pure, not the language".
Now, obviously you can't do I/O with pure functions1. This makes purely functional languages different from impure languages, where a function like (made-up semantics)
promptForName = do { print "What is your name"; getLine }
could be attributed the type String -> String
. But a functional language will generally have lots of other types beside just functions! ("Purely functional" does not mean "everything is a function" in the same way that "pure OO" means "everything is an object".) You can use any of those types to do I/O, if that's what you want that type for.
So the IO monad in Haskell is just a data type. A value of that type represents a list of I/O actions for the program to perform (basically). At runtime, the computer alternates between evaluating that list a little further and executing the actions described. But the evaluation does no I/O! That happens after the value's already been obtained.
1 Without defining additional semantics. You could say "a program is a function of type String -> String
; running it reads the contents of STDIN as a (lazy) string, applies the function to that string, and writes the resulting (lazy) string to STDOUT; but the entry point is the only function of type String -> String
in the program that has those semantics, so it's not really the function type doing the I/O here.
You can look at synchronous reactive languages like Lustre or Signal, for example. Those are languages dedicated to the specification of embedded reactive systems, based on data-flow programming.
You define functions that operate on values over time. Those functions can hold a state, in which case they are called nodes. In Signal, nodes and functions are different kind of processes. But the way the state is defined is by referring to previous values of flow variables.
So you could for example code a state machine by having an internal state variable. At each timestep, the new state is defined as a (pure) function of current inputs and the previous state.
When it comes to compiling those languages into, e.g. C, you get global variables that get overwritten inside a big for loop (the apparent antithesis of pure functional programming), but that's actually perfect in a context where static memory allocation and deterministic runtime execution are required.