Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re^13: Wassercrats::Improved Volume 0, Number 0

by jryan (Vicar)
on Sep 02, 2004 at 23:39 UTC ( [id://388170]=note: print w/replies, xml ) Need Help??


in reply to Re^12: Wassercrats::Improved Volume 0, Number 0
in thread Perl::Improved Volume 0, Number 0

Yeah, but the point is that variables can also encapsulate behaivor, and variables can also occupy a heirarchy of namespaces. So, a "global function" really isn't any better than a "global variable". They're both just globals.

  • Comment on Re^13: Wassercrats::Improved Volume 0, Number 0

Replies are listed 'Best First'.
Re^14: Wassercrats::Improved Volume 0, Number 0
by stvn (Monsignor) on Sep 03, 2004 at 00:19 UTC
    Yeah, but the point is that variables can also encapsulate behaivor, and variables can also occupy a heirarchy of namespaces

    Under certain circumstances this is true, but I would say its the exception rather than the rule. Unless of course you care to elaborate on what exactly you mean by "variables encapsulating behavior" outside of tied variables.

    So, a "global function" really isn't any better than a "global variable". They're both just globals.

    Yup, very true, just one more reason to always use packages, then your functions will never have to be global ;-)

    Although, I will say that the one (very important) difference between global functions and global variables is that one contains state and the other does not (barring things like closures and other assorted silliness). It is tracking all the state transistions that make global variable (all variables actually) difficult and unweildy.

    There is a reason why most functional languages either do not have assignment (Haskell), have single assignment variables (Erlang) or have large caveats surrounding their more imperiative features (LISP, ML, etc). A program is much easier to reason about and study when you dont have a rat's nest of state transitions to follow. If your program can be looked at as one giant (highly complex) expression, it becomes much easier to prove a level of 'correctness' for your program.

    -stvn
      If your program can be looked at as one giant (highly complex) expression, it becomes much easier to prove a level of 'correctness' for your program.

      Balderdash Functional programs have stacks and lists, and they are state. The difference is, that state is hidden, and nearly impossible to interogate. A misplaced parens can completely alter the behaviour of your "one giant (highly complex) expression" without ever raising an error.

      Quite how that makes it easier to prove correctness is beyond me.


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
        Functional programs have stacks and lists, and they are state.

        And trees and queues and hashes too, all of which can hold state, yes. But it's all about how you manage the state.

        In an imperative program, a variables state can change many times over the course of its life. If the variable has a relatively short scope, then it is not that hard to reason about the state of the variable at a given moment in the program. But when you introduce a number of variables, each with their own scopes, you start to get more complicated. When you introduce dependencies between the variables (if x == 5 then y must be < 2) the complexity of possible states which all your variables can be in at any given time increases radically. If we throw concurrency like threads into this, it becomes all but impossible to keep track of and adequately manage this programs state.

        In a functional program, your state is not a combination of a many sparsely related variables in their given scopes, but instead the current evaluated value of your expression. In a functional program your state is not spread across several variables, but instead is the input of the current expression. To reason about what your state will be at the end of the evalation of that expression, you need only look at the output of that expression. The transition to concurrency now also is much simplier since you need to not worry about one thread trampling on the state of another.

        Take these two uses of map as examples. First an imperative example which changes the state of an outside variable.

        my %hash = ( ... ); map { $hash{$_} = ($hash{$_} * 2) } keys %hash;
        Now the more functional approach.
        my %hash = ( ... ); my %new_hash = map { $_ => ($hash{$_} * 2) } keys %hash;
        The functional approach is non-destructive, it does not destroy the previous state, only creates a new (independent) one.

        IMO, badly used variables are a form of coupling. If function A needs to know about the possible variable state transistions caused by the independent execution of function B (a.k.a. - the side effects of B), then A and B are coupled. If function A need only understand that function B given a particular input will produce a particular value (and not affect global state) then it becomes much easier to seperate A from B.

        The difference is, that state is hidden, and nearly impossible to interogate.

        I don't understand this comment at all, the state is not hidden, it is the input of the current expression, how much more un-hidden can you get. They are the arguments to your current function. The state of a number of variables in an imperative program may be available, but you need to extend outside of your function to reach and interogate them.

        A misplaced parens can completely alter the behaviour of your "one giant (highly complex) expression" without ever raising an error.

        Clearly you have had a bad LISP/Scheme experience. To start with, not all functional languages are as paren-crazy as LISP/etc. But regardless, if you misplace a paren, thats a bug, sometimes the compiler/interpreter can catch bugs, sometimes it cannot, thats certainly not a purely functional langauge issue.

        Quite how that makes it easier to prove correctness is beyond me.

        It has a lot to do with the way theorems are proved in math (which was never my strongest subject). Think about getting the lenght of a list. You can make some statements about the length of a list.

        length []      = 0
        length (h::t) = 1 + length t
        
        Clearly the length of a list can be said to be 1 greater then the length of the tail of the list. If there is no list it is 0. It is very easy to then work this out for any possible case in a mathematically sound way.

        This then maps easily to a functional style of coding:

        sub length { my ($h, @t) = @_; return 0 unless defined $h; return 1 + length(@t); }
        I know my length function is correct, because it is built upon a statement which I can prove mathematically. Notice there are no variables in this example (with the exception of function parameters). An imperative approach would require the use of a temporary variable to hold state while some kind of looping construct (implemented in the language) loops through the variable, how would you go about proving that mathematically? (again math was not my strong subject, so I am not saying you can't, I am saying I don't know how and I imagine it would be much more complex).

        Also with a more functional, side-effect free approach, you get referential transparency. With referential transparency, you can rely on the fact that given a certain input, a functional will always produce the same output, not matter what. IMO, this is a very good thing. I can have confidence about what I will get back based upon what I put in, and therefore have a degree of certainty about the behavior of my program.

        And yes, I know that you can get all this with a disciplined imperative style, but the great thing about a functional style, is that you get it for free.

        And now its time for me to drink my morning coffee an get to work :)

        -stvn

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://388170]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (None)
    As of 2024-04-25 01:43 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found