|
cause the second one is a lot more convenient
|
# ? Sep 26, 2013 12:26 |
|
|
# ? May 16, 2024 18:18 |
|
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
|
# ? Sep 26, 2013 12:30 |
|
Pollyanna posted:what try thinking about lists in python and how they can be weird if you don't think about mutation Python code:
in a way you only get tuples
|
# ? Sep 26, 2013 12:32 |
|
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:
output depends on global state: Python code:
output affects global state: Python code:
|
# ? Sep 26, 2013 12:42 |
|
Symbolic Butt posted:try thinking about lists in python and how they can be weird if you don't think about mutation 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?
|
# ? Sep 26, 2013 12:44 |
|
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. 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
|
# ? Sep 26, 2013 12:48 |
|
isn't that an OOP thing, having methods associated with a type of variable?
|
# ? Sep 26, 2013 12:52 |
|
say you wanted to square every element of a listPython code:
weird fucked around with this message at 13:25 on Sep 26, 2013 |
# ? Sep 26, 2013 12:56 |
|
General Olloth posted:instead of being able to do no neither of those are functional because they mutate state
|
# ? Sep 26, 2013 12:57 |
|
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
|
# ? Sep 26, 2013 12:58 |
|
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...
|
# ? Sep 26, 2013 12:59 |
|
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.
|
# ? Sep 26, 2013 13:12 |
|
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. yeah, check this out: code:
|
# ? Sep 26, 2013 13:13 |
|
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
|
# ? Sep 26, 2013 13:14 |
|
Single assignment owns and hell yes functional programming chat
|
# ? Sep 26, 2013 13:14 |
|
Pollyanna posted:so the only way to define a sorted version of l is to say: 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
|
# ? Sep 26, 2013 13:18 |
|
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.
|
# ? Sep 26, 2013 13:19 |
|
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
|
# ? Sep 26, 2013 13:20 |
|
okay, so say i wanted to make a program return the number 7.Python code:
Python code:
Python code:
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.
|
# ? Sep 26, 2013 13:22 |
|
Pollyanna posted:lambda is new to me. i havent seen that before. 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:
|
# ? Sep 26, 2013 13:24 |
|
Pollyanna posted:lambda is new to me. i havent seen that before. 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:
code:
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 |
# ? Sep 26, 2013 13:29 |
|
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 |
# ? Sep 26, 2013 13:38 |
|
MononcQc posted:Yes and no. That depends on the language. Immutability and single assignment are not necessarily the same exact thing.
|
# ? Sep 26, 2013 13:39 |
|
Pollyanna posted:okay, so say i wanted to make a program return the number 7. Functional programming basically takes a more mathematical approach to things. So if you're in elementary school and the teacher tells you code:
code:
code:
code:
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:
|
# ? Sep 26, 2013 13:40 |
|
MononcQc posted:Yes and no. That depends on the language. Immutability and single assignment are not necessarily the same exact thing. 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 |
# ? Sep 26, 2013 13:41 |
|
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
|
# ? Sep 26, 2013 13:43 |
|
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
|
# ? Sep 26, 2013 13:44 |
|
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
|
# ? Sep 26, 2013 13:46 |
|
prefect posted:it almost seems like there are no variables, only constants values
|
# ? Sep 26, 2013 13:49 |
|
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/
|
# ? Sep 26, 2013 13:49 |
|
prefect posted:it almost seems like there is no dana, only zuul
|
# ? Sep 26, 2013 13:49 |
|
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. 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:
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:
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. 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.
|
# ? Sep 26, 2013 13:51 |
|
prefect posted:it almost seems like there are no variables, only constants lisp hackers do it bound
|
# ? Sep 26, 2013 13:53 |
|
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 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.
|
# ? Sep 26, 2013 13:54 |
|
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?
|
# ? Sep 26, 2013 14:07 |
|
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. this ruins my immersion
|
# ? Sep 26, 2013 14:07 |
|
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.
|
# ? Sep 26, 2013 14:11 |
|
crossquotin' because of this thread's hardon about ORMsBloody 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?
|
# ? Sep 26, 2013 14:17 |
|
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:
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 |
# ? Sep 26, 2013 14:19 |
|
|
# ? May 16, 2024 18:18 |
|
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)
|
# ? Sep 26, 2013 14:27 |