Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
Pollyanna
Mar 5, 2005

Milk's on them.


cause the second one is a lot more convenient

Adbot
ADBOT LOVES YOU

prefect
Sep 11, 2001

No one, Woodhouse.
No one.




Dead Man’s Band
i don't know the right answer to explain what functional programming is, but i think there are hints of it in here:

https://www.youtube.com/watch?v=iSmkqocn0oQ

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord

Pollyanna posted:

what

if f(x) is defined as x^2 - x + 1 then no matter what you put in for x you should get the same answer

why the hell would you get a different one???

try thinking about lists in python and how they can be weird if you don't think about mutation

Python code:
l = [4, 1, 7, 0]

print(sorted(l))  # prints [0, 1, 4, 7]
print(l)          # l is still [4, 1, 7, 0]

l.sort()
print(l)  # the sort() method mutates the original list so this prints [0, 1, 4, 7]
so basically this kind of behavior of the sort() method is not a thing in functional programming.

in a way you only get tuples :q:

qntm
Jun 17, 2009

Pollyanna posted:

what's the difference between functional programming and whatever you end up doing in python?

some examples of non-functional programming

unpredictable output:

Python code:
from os import stdin
def what:
    return stdin.readline()

print(what())
print(what()) # same function call, probably a different result
if you have referential transparency, the result from the first what() call can be stored, and you don't need to call it a second time. here, not so much.

output depends on global state:

Python code:
some_global_variable = 7

def butts(a, b):
    return a + b + some_global_variable

print(butts(5, 6)) # "18"

some_global_variable = 200008

print(butts(5, 6)) # same function call, same arguments, different result
with referential transparency, it doesn't matter when you call the function. without it, rearranging the final three (apparently unrelated) lines of code yields different results, which makes refactoring them dangerous

output affects global state:

Python code:
some_global_variable = ""

def fart():
    some_global_variable += "fart"
    return "whatever"

fart() # function call discards output
in functional programming, a function call which returns nothing or ignores the returned value is by definition a function call which does nothing, so it can be safely deleted.

Pollyanna
Mar 5, 2005

Milk's on them.


Symbolic Butt posted:

try thinking about lists in python and how they can be weird if you don't think about mutation

Python code:
l = [4, 1, 7, 0]

print(sorted(l))  # prints [0, 1, 4, 7]
print(l)          # l is still [4, 1, 7, 0]

l.sort()
print(l)  # the sort() method mutates the original list so this prints [0, 1, 4, 7]
so basically this kind of behavior of the sort() method is not a thing in functional programming.

in a way you only get tuples :q:

well yeah, in that first one you're just printing an array "sorted variable l", rather than making variable l equal to the array "sorted variable l". l.sort() and "l = sort(l)" would accomplish the same thing.

so youre saying that in functional programming, once you've set variable l equal to something, it will always be that, and that "l = sort(l)" would not be a valid command?

Salynne
Oct 25, 2007

Pollyanna posted:

well yeah, in that first one you're just printing an array "sorted variable l", rather than making variable l equal to the array "sorted variable l". l.sort() and "l = sort(l)" would accomplish the same thing.

so youre saying that in functional programming, once you've set variable l equal to something, it will always be that, and that "l = sort(l)" would not be a valid command?

instead of being able to do

l.sort()

you would have to do
l = sort(l)

sort would have to take an array and return the sorted array

it wouldn't be a function to call on an array

Pollyanna
Mar 5, 2005

Milk's on them.


isn't that an OOP thing, having methods associated with a type of variable?

weird
Jun 4, 2012

by zen death robot
say you wanted to square every element of a list
Python code:
def square_all_procedural(l):
    for i in range(0, len(l)):
        l[i] = l[i] * l[i]
    return l

def square_all_functional(l):
    # lambda makes anonymous functions
    return map(lambda x: x * x, l)

# map is predefined, but if it weren't, you could define it as:
def map(f, l):
    if l == []:
        return []
    else:
        return cons(f(l[0]), map(f, l[1:]))

# where cons is a function defined so that cons(1, [2,3]) returns [1,2,3]

weird fucked around with this message at 13:25 on Sep 26, 2013

weird
Jun 4, 2012

by zen death robot

General Olloth posted:

instead of being able to do

l.sort()

you would have to do
l = sort(l)

sort would have to take an array and return the sorted array

it wouldn't be a function to call on an array

no neither of those are functional because they mutate state

Salynne
Oct 25, 2007

VanillaKid posted:

no neither of those are functional because they mutate state

right yeah im dumb at least Im in the right thread for being dumb

Pollyanna
Mar 5, 2005

Milk's on them.


lambda is new to me. i havent seen that before.

also in that example, don't the for loop and the lambda do basically the same thing, if i'm reading it correctly?

VanillaKid posted:

no neither of those are functional because they mutate state

so the only way to define a sorted version of l is to say:

ls = sort(l)

? you can't change l itself? that doesn't seem like too much of a big deal...

weird
Jun 4, 2012

by zen death robot

Pollyanna posted:

you can't change l itself? that doesn't seem like too much of a big deal...

it takes time out of the equation. that makes it easier to reason about programs because you dont need to step through the order they'll be executed in to understand them. if youre doing multithreading, it means you dont need to worry about different threads stepping on each others' toes.

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord

Pollyanna posted:

well yeah, in that first one you're just printing an array "sorted variable l", rather than making variable l equal to the array "sorted variable l". l.sort() and "l = sort(l)" would accomplish the same thing.

so youre saying that in functional programming, once you've set variable l equal to something, it will always be that, and that "l = sort(l)" would not be a valid command?

yeah, check this out:

code:
Erlang R15B (erts-5.9)
> N = 7.
7
> N = 9.
"exception error: no match of right hand side value 9"

weird
Jun 4, 2012

by zen death robot
by having functions never rely on anything external to themselves, you also get more composable functions, which makes factoring things out easier. you repeat yourself less and get all the benefits of that

MononcQc
May 29, 2007

Single assignment owns and hell yes functional programming chat

prefect
Sep 11, 2001

No one, Woodhouse.
No one.




Dead Man’s Band

Pollyanna posted:

so the only way to define a sorted version of l is to say:

ls = sort(l)

? you can't change l itself? that doesn't seem like too much of a big deal...

i think i understand the philosophical point about not reusing variable names (or reassigning them, or whatever the technical term would be), but it feels awfully strange

MononcQc posted:

Single assignment owns and hell yes functional programming chat

i was hoping we'd summon one of you to explain things to us in small words :neckbeard:

Johnny Cache Hit
Oct 17, 2011
lol i was going to type a response to polyanna when i got into work rather than phonepost but all the cool and smart kids came out and now MononcQc is here and this functional programming chat is about to get seriously educational, its a good day in the pos.

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder
the first programming language i ever got serious about was haskell and i thought i understood it okay until i tried programming xmonad

no idea how that poo poo works

Pollyanna
Mar 5, 2005

Milk's on them.


okay, so say i wanted to make a program return the number 7.

Python code:
x = 2

x = 2 + 5

print x
in functional programming (as opposed to whatever the other thing was, procedural was it?) this will not work, nor will:

Python code:
x = 2

x = x + 5

print x
so in that case, why not just write:

Python code:
x = 2

y = x + 5

print y
it's the same amount of lines and characters. so functional programming wants to conserve variables because, say you want to know what variable x is. you see that x = x + 5, but you don't really know what value is assigned to x is so you're like "wtf does that mean x = (x + 5) + 5 ad infinitum or sth". so you'd have to look backwards through the program to see what the initial state of x was in order to execute the function.

so functional programming doesn't like that, and prefers x = 2 and y = x + 5? but wouldn't the steps basically be the same for that? you'd see that y = x + 5, but you don't know what x is, so you look backwards in the program for x's initial state...

you see what i mean? it's the same number of steps.

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord

Pollyanna posted:

lambda is new to me. i havent seen that before.

also in that example, don't the for loop and the lambda do basically the same thing, if i'm reading it correctly?

yes, pretty much. VanillaKid is just showing you the pure functional way of doing these things but actually doing it with a list comprehension is a better way to do it in python:

Python code:
def square_comprehension(l):
    return [x*x for x in l]

MononcQc
May 29, 2007

Pollyanna posted:

lambda is new to me. i havent seen that before.

also in that example, don't the for loop and the lambda do basically the same thing, if i'm reading it correctly?


so the only way to define a sorted version of l is to say:

ls = sort(l)

? you can't change l itself? that doesn't seem like too much of a big deal...

Yes and no. That depends on the language. Immutability and single assignment are not necessarily the same exact thing.

Let's say I have a tree T:

code:
      d
    /   \
   b     g
 /  \   /  \
a    c f    h
Now let's say my code does:

code:
Old = T, % regular assignment
New = Old,
New = insert(e, New)
Now here, in a language like Erlang or Haskell or whatever, you would crash (or not compile) because you're trying to change the value of a variable. However, nothing keeps you from having a language where you allow that as long as Old remains usable, and New =/= Old once the update has taken place.

This can be done with immutability, which pretty much all functional languages support. When you update the tree, nodes that are in common are kept, and otherwise part of the tree points to the old one, giving you something a bit like this in memory:



Basically, the entire unchanged subtree starting at b is kept for both Old and New trees, but the rest changes in some way. The h node is also shared because it had no reason to change. The F node had to be copied and rewritten to allow to change what child it has, but note that if the content of F is large, that can be copied literally. I.e. if my node is {Current, Left, Right}, I need to change the node, but could still point to the existing 'Current' value from the older tree.

Garbage collection will later determine what can be reused or not. This lets you update trees in O(log n) memory as well as time, rather than O(n) memory if no sharing took place and deep copies were needed, regardless of the content of the nodes.

So single assignment is often used, but is not necessary for a language to be immutable.

In the case above, doing the update and allowing New to point to the tree in red would work, and Old could still keep its references intact and also work, despite New (the variable) changing definition over time. The data structure remained safe for all its users, though.

MononcQc fucked around with this message at 13:33 on Sep 26, 2013

gonadic io
Feb 16, 2011

>>=
As alluded to earlier, functions being pure means that you can guarantee that there aren't any side effects and you're free to reorder them if you want. In practice this means that concurrency (i.e. splitting work over multiple cores) is very very easy and safe because if I have a list [Butts] then I know that computing the first half of the list on core A and the second half on core B won't break anything.

In C, Java, Python you can do the same thing but you can't really enforce that your code doesn't break poo poo or affect other computations. Your options are 1) comb through the source yourself or 2) test and pray*.

This really came up in Software Transactional Memory which is a way of avoiding deadlocks in parallel code originally designed for C#. However the presence of side effects meant that they couldn't get it working reliably and then it got put into Haskell instead and is awesome.

p.s. check out http://learnyouahaskell.com/ or http://learnyousomeerlang.com/

*: possibly a third option of some hacky immutable/static/final/don't_touch_me compiler flags?

gonadic io fucked around with this message at 13:41 on Sep 26, 2013

power botton
Nov 2, 2011

MononcQc posted:

Yes and no. That depends on the language. Immutability and single assignment are not necessarily the same exact thing.

Let's say I have a tree T:

code:
      d
    /   \
   b     g
 /  \   /  \
a    c f    h
Now let's say my code does:

code:
Old = T, % regular assignment
New = Old,
New = insert(e, New)
Now here, in a language like Erlang or Haskell or whatever, you would crash (or not compile) because you're trying to change the value of a variable. However, nothing keeps you from having a language where you allow that as long as Old remains usable, and New =/= Old once the update has taken place.

This can be done with immutability, which pretty much all functional languages support. When you update the tree, nodes that are in common are kept, and otherwise part of the tree points to the old one, giving you something a bit like this in memory:



Basically, the entire unchanged subtree starting at b is kept for both Old and New trees, but the rest changes in some way. The h node is also shared because it had no reason to change. The F node had to be copied and rewritten to allow to change what child it has, but note that if the content of F is large, that can be copied literally. I.e. if my node is {Current, Left, Right}, I need to change the node, but could still point to the existing 'Current' value from the older tree.

Garbage collection will later determine what can be reused or not. This lets you update trees in O(log n) memory as well as time, rather than O(n) memory if no sharing took place and deep copies were needed, regardless of the content of the nodes.

So single assignment is often used, but is not necessary for a language to be immutable.

In the case above, doing the update and allowing New to point to the tree in red would work, and Old could still keep its references intact and also work, despite New (the variable) changing definition over time. The data structure remained safe for all its users, though.

:allears:

MononcQc
May 29, 2007

Pollyanna posted:

okay, so say i wanted to make a program return the number 7.

<...snip...>

so functional programming doesn't like that, and prefers x = 2 and y = x + 5? but wouldn't the steps basically be the same for that? you'd see that y = x + 5, but you don't know what x is, so you look backwards in the program for x's initial state...

you see what i mean? it's the same number of steps.

Functional programming basically takes a more mathematical approach to things.

So if you're in elementary school and the teacher tells you

code:
One = 1
Two = 2
Three = One + Two
Four = Two + Two
Four = One + Three
You should be able to freely substitute:


code:
3 = 1 + 2
4 = 2 + 2
4 = 1 + 3
However, when programmers come in and decide that variables are actually memory locations and these can be modified, precious mathematicians feel confused because:

code:
One = 1
Two = 2
Three = One + Two
Four = Two + Two
Four = One + Three
One = Two
Four = One + Two
Would be substituted as

code:
3 = 1 + 2
4 = 2 + 2
4 = 1 + 3
1 = 2
4 = 1 + 2
Which is visibly weird and hard to think about! Functional programming with regards to variables isn't about being economical on lines and whatnot, but more or less about using variables the way mathematicians can use them -- a fixed value you can reason about, and not a memory location or pointer or less abstract concept.

Because of that, making variables immutable works fairly well. In some languages with single assignment, you can reassign to variables as long as the value remains the same. So that:

code:
x = 1,
x = 0+1,
x = 2
will work for the first 2 assignments, but will raise an exception (or crash, or won't compile) on the third one, as if it were an assertion.

Pollyanna
Mar 5, 2005

Milk's on them.


MononcQc posted:

Yes and no. That depends on the language. Immutability and single assignment are not necessarily the same exact thing.

Let's say I have a tree T:

code:
      d
    /   \
   b     g
 /  \   /  \
a    c f    h
Now let's say my code does:

code:
Old = T, % regular assignment
New = Old,
New = insert(e, New)
Now here, in a language like Erlang or Haskell or whatever, you would crash (or not compile) because you're trying to change the value of a variable. However, nothing keeps you from having a language where you allow that as long as Old remains usable, and New =/= Old once the update has taken place.

This can be done with immutability, which pretty much all functional languages support. When you update the tree, nodes that are in common are kept, and otherwise part of the tree points to the old one, giving you something a bit like this in memory:



Basically, the entire unchanged subtree starting at b is kept for both Old and New trees, but the rest changes in some way. The h node is also shared because it had no reason to change. The F node had to be copied and rewritten to allow to change what child it has, but note that if the content of F is large, that can be copied literally. I.e. if my node is {Current, Left, Right}, I need to change the node, but could still point to the existing 'Current' value from the older tree.

Garbage collection will later determine what can be reused or not. This lets you update trees in O(log n) memory as well as time, rather than O(n) memory if no sharing took place and deep copies were needed, regardless of the content of the nodes.

So single assignment is often used, but is not necessary for a language to be immutable.

In the case above, doing the update and allowing New to point to the tree in red would work, and Old could still keep its references intact and also work, despite New (the variable) changing definition over time. The data structure remained safe for all its users, though.

nice. that makes a lot of sense. in your example, haskell and erlang are immutable AND single assignment, right? hence why you can't change New. in languages that are immutable but not single assignment, you can still change New.

the way i had understood the whole "x = 1, y = x, print y + 1" thing is that like...there's a difference between y being equal to the same value/string/whatever that x is, and y being literally equal to x (like a nickname or alias). in long form, it'd be "y is equal to x, which is equal to 1, therefore y is equal to 1" as opposed to "y is x". does that make sense?

i don't quite see either of those in your example, cause it kinda ends up being a mix of the two. i had envisioned either an entirely new tree (i.e. a copy of all nodes rather than directly affected nodes) or the old tree with an e node attached to f. instead, it looks like it's trying to conserve energy or something by doing the bare minimum it needs to change. meaning, it creates new stuff for what changes, but what doesn't change already exists somewhere in memory, so it just points back to that.

is that correct?

edit: oh you responded, lemme read that

Pollyanna fucked around with this message at 13:43 on Sep 26, 2013

Bloody
Mar 3, 2013


i like how this diagram was designed to look like it was hand-drawn but clearly is not hand-drawn because it actually features like 2 distinct non-circles and font-consistent handwriting

Pollyanna
Mar 5, 2005

Milk's on them.


Bloody posted:

i like how this diagram was designed to look like it was hand-drawn but clearly is not hand-drawn because it actually features like 2 distinct non-circles and font-consistent handwriting

yeah how did you make that

prefect
Sep 11, 2001

No one, Woodhouse.
No one.




Dead Man’s Band

MononcQc posted:

Which is visibly weird and hard to think about! Functional programming with regards to variables isn't about being economical on lines and whatnot, but more or less about using variables the way mathematicians can use them -- a fixed value you can reason about, and not a memory location or pointer or less abstract concept.

it almost seems like there are no variables, only constants

gonadic io
Feb 16, 2011

>>=

prefect posted:

it almost seems like there are no variables, only constants

values

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

Pollyanna posted:

yeah how did you make that

it looks like it came from here to me but i could be wrong

http://learnyouahaskell.com/

Pollyanna
Mar 5, 2005

Milk's on them.


prefect posted:

it almost seems like there is no dana, only zuul

MononcQc
May 29, 2007

Pollyanna posted:

nice. that makes a lot of sense. in your example, haskell and erlang are immutable AND single assignment, right? hence why you can't change New. in languages that are immutable but not single assignment, you can still change New.
is that correct?

Yes. Erlang and Haskell are both immutable and single assignment. In languages without single assignment and immutability, you can still change new indeed. Elixir does this on the BEAM virtual machine, for example. You can coerce a variable to be single assignment by prefixing with ^ so that:

code:
x = 1
x = 2
^x = 3
Will work up until the last expression, where ^x tells the compiler (or interpreter) "please reuse the 'x' from the previous value rather than reassigning".

Pollyanna posted:

the way i had understood the whole "x = 1, y = x, print y + 1" thing is that like...there's a difference between y being equal to the same value/string/whatever that x is, and y being literally equal to x (like a nickname or alias). in long form, it'd be "y is equal to x, which is equal to 1, therefore y is equal to 1" as opposed to "y is x". does that make sense?

You're generally free from thinking that way in functional languages. You care about values not how they are represented. Basically I could do:

code:
x = [1,2,3,4]
y = x
x = append([1,2], [3,4])
x = y
and have it work fine. In the case of x = append([1,2], [3,4]) the program could determine that the result of append([1,2], [3,4]) is equivalent to x because it compares equal.

It could also use the fact that x and y both have the same pointer to the same data structure when executing x = y so that (given you're immutable) you can stop comparing further and say the expression worked fine.

It's just an implementation detail how you deal with the comparison, but we're dealing with values from the user's perspective here.

Pollyanna posted:

i don't quite see either of those in your example, cause it kinda ends up being a mix of the two. i had envisioned either an entirely new tree (i.e. a copy of all nodes rather than directly affected nodes) or the old tree with an e node attached to f. instead, it looks like it's trying to conserve energy or something by doing the bare minimum it needs to change. meaning, it creates new stuff for what changes, but what doesn't change already exists somewhere in memory, so it just points back to that.

is that correct?

You could do it with two trees entirely and it would work fine by the semantics required. However, it would be inefficient in memory because you'd end up rewriting a shitload of data on every update on a large data structure, and trashing around inefficiently.

Reusing the old tree lets you be more efficient in memory (and processing time) by indeed doing the bare minimum needed. Think of the same diagram if you made 70 updates. It's more efficient to reuse old trees than to have 70 new ones.

weird
Jun 4, 2012

by zen death robot

prefect posted:

it almost seems like there are no variables, only constants

lisp hackers do it bound

MononcQc
May 29, 2007

Bloody posted:

i like how this diagram was designed to look like it was hand-drawn but clearly is not hand-drawn because it actually features like 2 distinct non-circles and font-consistent handwriting

It was originally hand-drawn, then put on a computer. I originally had my own handwriting for most of the drawings, but when I ended up doing the paper version, I (and my girlfriend, who retraced a shitload of illustrations to help me) used a handwritten font to make it more readable to everyone.

Many of these drawings though, when traced back, were using only 2-3 circles because gently caress retracing over all of them. Some are just rotated to give the impression of being handdrawn 100% of the time, but I had more things to do than carefully draw every circle all over again. The same circles are probably used in a bunch of places in the book, but the original ones are drawn by hand.

You can see that the C node is just the D node flipped over, for example.

USSMICHELLEBACHMAN posted:

it looks like it came from here to me but i could be wrong

http://learnyouahaskell.com/

It comes from the printed version of http://learnyousomeerlang.com -- the drawing I posted above only made it in the final print copy of the book and won't be on the website though.

Pollyanna
Mar 5, 2005

Milk's on them.


so functional programming has the advantage of being memory efficient? that would mean programs would run faster and take up less ram and such, right?

Bloody
Mar 3, 2013

MononcQc posted:

It was originally hand-drawn, then put on a computer. I originally had my own handwriting for most of the drawings, but when I ended up doing the paper version, I (and my girlfriend, who retraced a shitload of illustrations to help me) used a handwritten font to make it more readable to everyone.

Many of these drawings though, when traced back, were using only 2-3 circles because gently caress retracing over all of them. Some are just rotated to give the impression of being handdrawn 100% of the time, but I had more things to do than carefully draw every circle all over again. The same circles are probably used in a bunch of places in the book, but the original ones are drawn by hand.

You can see that the C node is just the D node flipped over, for example.


It comes from the printed version of http://learnyousomeerlang.com -- the drawing I posted above only made it in the final print copy of the book and won't be on the website though.

this ruins my immersion

MononcQc
May 29, 2007

Symbolic Butt posted:

pure functional programming is stuff like ml, haskell, erlang, lisp...

I wanted to comment on this one thing here.

"Pure" functional programming is a specific type of functional programming, where side-effects are forbidden not just in the data structures, but also in input/output, to name one. The difference is that in a lisp (or Erlang), we don't give a poo poo about side-effects. In fact, Erlang message passing is a side-effect and the entire language relies on it as one of its basic principles.

It means that if I call (some-call x y) in Scheme and get a 2 back, I don't have a guarantee that some-call won't do poo poo like logging, writing to disk, or uploading my SSN without me knowing, every time I call it.

In a pure language (and not all pure languages are functional -- Mercury is a pure logic language), this kind of side-effecty operation is forbidden unless it's in the right context.

In Haskell, that special context is a monad. The special context you use can impose restrictions on how you can do or call your side-effects.

For example, you could say that all side-effecting functions can call pure functions, but not the opposite. In that way, you let your compiler be free to do all the optimizations it wants on the pure parts of the programs: caching/memoizing, inlining, automatic parallelism, make it lazy, etc. but forbid it to play with the flow of the impure program.

This tends to change the way programmers in these language think about software in major ways, and the gymnastic of forcing your side-effecting operations to all be explicitly marked as such can both be extremely frustrating when you're not used to it, and sane (and possibly safer) when you get to intuitively separate pure from impure code.

coffeetable
Feb 5, 2006

TELL ME AGAIN HOW GREAT BRITAIN WOULD BE IF IT WAS RULED BY THE MERCILESS JACKBOOT OF PRINCE CHARLES

YES I DO TALK TO PLANTS ACTUALLY
crossquotin' because of this thread's hardon about ORMs

Bloody posted:

excellent, excellent. next problem: i want to do database things from a c# app. every previous time ive used a db ive used some sort of orm. i dont know how to write sql more complex than select * from butts where farts = something or whatever. also i really like that orms easily give strongly-typed results. what database should i use (mssql because c#?) and how do i do things as strongly typed as possible?

MononcQc
May 29, 2007

Pollyanna posted:

so functional programming has the advantage of being memory efficient? that would mean programs would run faster and take up less ram and such, right?

That really depends on the language. Historically, and 99% of the time, the answer is no, functional programs are not more memory efficient. Mutable languages will either do the same kind of sharing, or will just update poo poo directly in memory in a destructive manner so that there is no sensible overhead to modifying existing data structures.

What that tradeoff does, however, is force the programmer to be more disciplined about how they hold outdated references to some data structures (you thought A was in there but it's gone now!), and thinking of all the ideas of references vs. values and whatnot. You don't really care about this in functional programming most of the time.

Some languages are formal enough in how they're designed that you can do an analysis of the data flow of some data structure and figure out that "you know what, it wouldn't hurt anybody if this one operation here was destructive" and you do it. In these cases, when you play in that flow, you can get similar memory efficiency to imperative or OO (or just generally destructive) languages. In practice, this rarely happens, although I don't have extensive experience with such languages.

There's also a special kind of types (Rust uses them iirc) where you can say "it's fine, I'm usually functional, but in this case, I want to go destructive". What these types will do is let you use the language as before, but when you do some poo poo as:

code:
Old = T,
New = insert(e, Old)
print(Old)
The compiler will tell you that you can't reuse Old in print(Old) after it has been update as New. Basically, these type systems will let the compiler enforce a thing where you write programs as if they were immutable, but will warn you and yell at you when you reuse older values.

Because you added that constraint to your language, the language is now free to do destructive operations on the data structures while being 100% safe on data access from older references.

Few languages use that kind of type system, but it's kind of neat to think about.


PS: there are cases where functional languages will use less memory than OO or imperative ones, but that will usually be the result of different things and optimizations being available to the compiler or the runtime to obtain similar objectives, and usually not a direct result of the fact that the language is immutable.


E: the types I mention in this post are Uniqueness types or more generally linear type systems

MononcQc fucked around with this message at 14:28 on Sep 26, 2013

Adbot
ADBOT LOVES YOU

coffeetable
Feb 5, 2006

TELL ME AGAIN HOW GREAT BRITAIN WOULD BE IF IT WAS RULED BY THE MERCILESS JACKBOOT OF PRINCE CHARLES

YES I DO TALK TO PLANTS ACTUALLY

MononcQc posted:

Garbage collection will later determine what can be reused or not. This lets you update trees in O(log n) memory as well as time, rather than O(n) memory if no sharing took place and deep copies were needed, regardless of the content of the nodes.

theoryspergin': only true on balanced trees. trees in general it can be O(n) b/c their height can be O(n)

  • Locked thread