1. Stop creating counters/loops and become facile with map, reduce, and the like. This will shift your thinking away from blocks and toward functions.
2. Take the time to really understand what side effects are, and start avoiding them everywhere they are not necessary. Keep scopes as local as is practical.
3. When you start toying with functional programming per se, make sure you really have your head around recursion. That's where much of the magic concision comes from.
I then moved to FP-TS, which makes more heavy use of haskell-like patterns and monads.
The hard part isn't the syntax of whatever language, but understanding the new patterns and way of thinking, which you can do with a simulation layer like FP-TS (for typescript/javascript).
The functional patterns and emphasis on types makes your code robust and more correct. It emphasizes correctness, which is ultimately what your job is as a programmer. Optimization comes after.
Though other people at my work dislike it due to them not understanding what's going on
I would want to program in functional too, but I would seek out projects or teams that already use functional. I’d never introduce a functional language to an already established team or project, unless of course, I was the CTO and there were clear benefits.
Agreed that functional patterns can be hard to understand if you don't know the patterns, but if you do know them they are much easier to understand and reason about the code. It's a long term investment, and one that frankly I believe will be inevitable as more and more people start doing programming work.
There's a lot of resistance to adopting anything with the name functional, and that resistance is often seen in a /refusal/ to try to understand instead of a mere lack of understanding: people put up walls straightaway. I expect many need motivating examples to guide them to it.
Languages like Kotlin are pointing the way towards that middle ground far more effectively than, say, Scala did.
Disagree. This is likely to 'dilute' the lessons of functional programming, as it were. If you learn to program in idiomatic Clojure/OCaml/Haskell/Scheme, you can be relatively sure you really have picked up the principles of functional programming.
If you merely attempt to apply new principles in an environment you're already comfortable in, things aren't going to 'click' in the same way.
Beside that, plenty of languages simply lack the facilities needed to effectively use the concepts of FP, as vmchale says.
In non-FP languages, I didn't originally appreciate the benefits of the pattern. It was more work to do things functionally, so I dismissed some patterns that were actually useful.
I'm a bit biased, but would recommend Elixir as an accessible FP language. It has an accessible syntax and modern tooling.
You may be frustrated with the constraints of immutability for a few weeks, but the benefits become apparent once you're used to it.
Now when I work in non-FP languages like JavaScript, I will apply FP principles when it makes sense.
Other unique French US cultures:
Haitian Creole
New England French were are Canadian migrants.
Missouri French
Muskrat French from Michigan
North Dakoka Metis French
It could have come to some from 40 years old but it was already here for many.
Still it's a French word. It is like going to Germany and learning an English word but calling it German.
(edit: spelling)
For a simple example, val newList list.map(function Call(_))
Instead of val1 = functionCall(1) valN = functionCall(N)
The ideas themselves are not particularly complicated, but I hadn't previously worked with abstractions where the default was to operate on whole data structures rather than on individual elements, so I didn't see how you would set up your program to make those functions useful. In addition, for abstract higher-order functions, type signatures help a lot for understanding how the function operates. I found `functools.reduce(function, iterable, initializer)` significantly more opaque than `foldl :: (b -> a -> b) -> b -> [a] -> b` because the type signature makes it clear what sort of functions are suitable for use as the first argument.
It's now easy for me to use the same abstractions in any language that provides it because I only have to learn the particular encoding of this very general idea. While I couldn't figure out why functools.reduce was useful or desirable, I couldn't figure out many parts of C++'s standard template library at all. But if you already know the core concepts and the general way that C++ uses iterators and the fact that functools.reduce, Data.Foldable.foldl, and std::accumulate[4] are all basically doing the same thing for the same reasons is a lot more readily apparent.
[0] https://docs.python.org/3/library/functools.html#functools.r...
[1] https://docs.python.org/3/library/itertools.html#itertools.s...
[2] https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-...
[3] https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-...
That's a good point. Using a proper functional programming language doesn't just enable FP ideas (you can't fake a feature like implicit capture of variables), it may also clarify them by reducing baggage.
> I found `functools.reduce(function, iterable, initializer)` significantly more opaque than `foldl :: (b -> a -> b) -> b -> [a] -> b` because the type signature makes it clear what sort of functions are suitable for use as the first argument.
I suspect you're just a better Haskell programmer than me (I've only ever dabbled), but I find the big-mess-of-arrows syntax to be pretty confusing compared to a simple tuple of descriptively named identifiers.
Perhaps related to this: I don't see the practical appeal of currying. Even C++ supports the 'bind' pattern just fine - http://www.cplusplus.com/reference/functional/bind/#example
xargs is analogous to map() in this situation, and the script needs to have limited side effects to work well with concurrency. xargs -P4 for example.
But at least make sure that your language supports closures.
Later I read a couple of chapter of SICP and then I really changed and my programming hasn't been the same since. The language I use at work is JavaScript and while SICP isn't for JavaScript, nothing else has changed my JavaScript for the better to that degree.
There's a port. https://sicp.comp.nus.edu.sg/
I am not very comfortable with this. How can I learn to do this in traditionally non-FP languages like Java? (Am CS undergrad student)
https://developer.ibm.com/technologies/java/series/java-8-id...
List of articles relating to idiomatic Java 8 code. Some of these touch on using lambdas and functional idioms.
https://developer.ibm.com/articles/j-java8idioms3/
This one shows a few of the functional-styled methods that can be used (foreach, takewhile, iterate, etc.).
https://developer.ibm.com/articles/j-java8idioms2/
Shows the collection pipeline pattern.
I have experience with the same things in C# and other languages, the way they're using them in these articles are what I'd expect from a comparable API.
MAP: Take a collection, say a list/array or a dictionary/hash, and perform some function on each member of the collection, returning a new collection who's members are the return values for each original member. It's a loop, but no loop!
REDUCE: Do the same thing as map, but carry along an output variable, and have your function's output for each member (potentially) mutate that output variable. Summing is a basic example.
I'm not specifically recommending preferring this in Java as a step towards functional programming. It's in, uh, more terse languages like Python and Ruby where the payoff is obvious [1][2]. And among not-functional programming languages, it's not just dynamic languages, either. Consider Dart (and seriously, consider Dart) [3]. Also, Javascript, which has had many features shoehorned-in over the years, has these and related functions.
[0] https://www.java67.com/2016/09/map-reduce-example-java8.html
[1] Double some numbers Python: result = map(lambda x: x + x, array_of_numbers)
[2] In Ruby: result = array_of_numbers.map{|x| x + x}
[3] In Dart: result = arrayOfNumbers.map((x) => x + x).toList();
My school (Macalester College) recently started introducing some fp constructs/concepts in our intro class such as map, reduce like you mentioned.
It was long after I took it and now I am TA-ing. Oddly enough, I am more comfortable approaching this style in Kotlin.
But then you don't get any of the newer stuff.
If you haven't learned to touch type (it happens, I didn't learn until I was 22), then first learn that, then learn vim.
FYI: Remap your capslock key to escape to use Vim more effectively.
https://stackoverflow.com/questions/28444740/how-to-use-vi-m...
If you are using zsh, you need to add this to ur .zshrc
autoload -z edit-command-line
zle -N edit-command-line
bindkey "^X^E" edit-command-line set -o vi
Starts you in insert mode. To go back to the usual command-line editing, set -o emacsThat's more one way of doing things rather than a "FYI". Eg I switched capslock with ctrl. There are many ways to exit insert mode, I prefer:
inoremap jk <esc>
inoremap kj <esc>inoremap <esc> <nop> as this helps you train your fingers to stop using <esc>
If you're really curious, just learn to touch type and find out. It doesn't take all that long if you're already a solid typist. I'd be fascinated to read an article from someone who learned how to touch type and thought it was a waste of time.
<Esc> or CTRL-[ End insert or Replace mode, go back to Normal mode. Finish abbreviation.
CTRL-C Quit insert mode, go back to Normal mode. Do not check for abbreviations. Does not trigger the InsertLeave autocommand event.
I installed it a couple years ago, went whole hog, down the rabbit hole, but realized a couple of things.
1. I rarely ever use anything more than a simple L/R split.
2. When I do use something more complex, it's almost always in the terminal, in which case why not use tmux?
These days I'm back to using gnome because ubuntu switched to it over unity (which had a weird multitouch bug that drove me crazy).
What do you get out of i3 beyond a simple L/R split supported by simpler wms and how often do you use it?
I use i3 with polybar and have dedicated workspace icons (web browser, terminal, editor, to-do, email, music, etc) for quick navigation between different applications. Over time I’ve built up muscle memory (i.e $Mod+3 will bring me to my editor) that has significantly sped up my development process. While you could use another window manager for a similar purpose, I find the relatively minimalist approach of i3 + polybar in my case to be fast and highly configurable.
Us the toggle an i3 concept? I’m interested in it, can you give me the function name so I can look up doco? :)
I treat each workspace as dedicated for a specific purpose - Dev, Browsing, Chat, etc. That gives me quick mnemonics to hop to each space: MOD+1, MOD+2, MOD+3, ...
Within my Dev workspace, I use a tabbed pane for top-level organization: browsers (stacked), IDE, terminal, Emacs (magit + org), etc. This keeps my focus on that space when doing dev, and away from the laptop monitor, which is only occasionally useful as a reference.
I'll occasionally stack a terminal beneath my IDE if the current task requires it, e.g. to test a deployment or a project task.
1. Workspaces. Not at all unique to i3 but I’ve kept mine themed and automatically load certain apps into the same workspaces—all things i3 makes easy to do.
2. Floating scratchpad for media player. Nice to have my music controls always accessible but only visible when I unhide them.
3. Vertical split beneath my editor with a terminal. Just my personal preference, but I typically have L/R with code/browser and then split the code half vertically.
Being able to move windows across displays and workspaces quickly are other pluses, but again, not at all i3 exclusive.
It means I can have an overview of a bunch of different things and keep terminals context-specific (1 terminal for htop, 1 for docker, 1 for whatever remote test environment, 1 for project A, 1 for project B, 1 for some other remote host I need for some reason, etc.) If I want to do a new task unrelated to anything I'm doing before, I don't need to break the context of an existing terminal, I just press Alt+Enter, it's automatically slotted into a place where it's completely visible and usable and I can do that task quickly. When I'm done, I can close it, again, without disturbing the context of all the other terminals. It's just incredibly freeing to have that and I feel it frees a lot of cognitive load by being able to go back to a terminal for a certain task and immediately see exactly where I was and what I did last.
Also, much like the other comments, I use task-specific virtual desktops all the time. First desktop is for all the terminals. Second is for browser/communication. Third is for project A. Fourth is documentation related to projA. Fifth is projB. Sixth can be more documentation. I often have 10 virtual desktops for different things. I don't want to imagine what it'd look like if I had it all on one desktop.
https://stackoverflow.com/questions/5120399/setting-windows-...
https://stackoverflow.com/questions/45411844/before-diving-i...
I sometimes do move to more of a tmux split workflow, especially if I'm working on remote machines, but it's just much nicer to have the same keyboard commands for all of my windows.
Currently I use i3 with packages pulled in from XFCE to handle sessions and power management, plus xfce4-appfinder and xfce4-panel (started and killed with MOD keys of course) because I wanted something beyond d-menu / b-menu.
It all works very well and was easy to configure.
This would not be possibly if I wasn't using 4k monitors. That was a big shift for me, because now I think of each 4k monitor as 4 1080p displays.
(Sidenote: is there any sort of linux libvte-based terminal emulator that has tmux integration a-la iTerm2? For when I do use i3, it would be really nice if I could spawn a new terminal on a remote server, attaching through an existing tmux session.)
1: https://unix.stackexchange.com/questions/189805/what-termina...
I've been toting around the same .vimrc for like 6 or 7 years and there are so many better plugins now.
Vim has been probably the most profitable tool I've ever picked up. Or maybe git. But I think Vim.
Jupyter Notebook: https://github.com/lambdalisue/jupyter-vim-binding Jupyter Lab: https://github.com/jwkvam/jupyterlab-vim
It lets you modify and save code from the quickfix buffer, so when you search for something and it shows up in the qf, you can do a find replace / edit / etc. This is especially great for mass refactoring / renaming.
The reason I end up ditching Vim after a few weeks every time I try it (4 serious attempts now) and go back to IntelliJ (which I’ve used for two decades) is that I never found a solution to the following trivial issue:
Imagine you have a large Java codebase and you want to refactor all occurrences of a method called “doFoo()” to give it a better name - how do you do this in Vim?
This is a single keypress in IntelliJ and I use this function very frequently but I never found a way to do it in Vim.
Note: I only want to change THIS doFoo() method, not the hundred other doFoo() methods in the codebase.
Also note: yea, this includes all implementations of the interface, all abstract classes, all classes that extend a a class that implements the interface and all other funky polymorphic things, and NO unrelated code. And do it all in one keypress, don’t have me manually go through line by line.
Any ideas if this is possible now?
https://github.com/eclipse/eclipse.jdt.ls
https://github.com/georgewfraser/java-language-server
Are both good examples. You'll need a corresponding client like this one
https://github.com/prabirshrestha/vim-lsp
There are others, but this one is pretty good. Next release of Neovim will have one built into the editor. Frankly, it's a bit of a hassle but once you get an LSP provider set up you can get one for just about any language you're using
That being said the first thing I do after installing IntelliJ is open the plugin settings and install IdeaVim.
I use Emacs for a tonne of stuff, and basically any other language I use. But for Java, with its deeply hierarchical codebases and general verbosity, there's just no sane way to manage that complexity smoothly without a good IDE.
(One could argue that if a language necessitates an IDE to work with it, then that's a failure of the language's DX. But thats an entirely separate discussion.)
So you get all the powerful IDE commands and the high speed of Vim commands at the same time.
It's easy to set up !
[alias] dfif = diff idff = diff grpe = grep
I have often wondered why that functionality disappeared, and why no one has tried to resurrect it. Search engines offer corrections all the time; why doesn't bash?
Teitelman's Interlisp
Has a DWIM feature that's
Really a screw;
MACLISP has evident
Superiority
Letting its customer
Mean what he do.
--The Great Quux (Guy L. Steele)
This poem indicates the frustrations that hackers had with DWIM at the time, which may explain why no one tried to resurrect it. Too-clever-by-half features intended to help tend to drive people nuts, especially when they fail. Even when they succeed, they interrupt the user's flow and become like that dialog box Windows users just dismiss.
# I do this an embarrassing amount
alias fgf='fg'
alias fgfg='fg'
alias gf='fg'
alias gfg='fg' alias emcas='emacs'
alias emac='emacs'
alias emasc='emacs'
alias enacs='emacs'
alias emas='emacs'
alias emascs='emacs'
alias eamcs='emacs'
alias eemacs='emacs'Honourable mention also to FZF [1] which not only makes it trivial to locate a file in a directory tree, but has revolutionised my history use with its fuzzy matching.
gc = git checkout
gs = git status
etc...
alias g="git"
__git_complete g _git # enable git autocompletion (braches, etc.)
alias gc="git commit -am"
alias gp="git push"
__git_complete gp _git_checkout # checkout is more useful than _git_push because it autocompletes the branch
alias ga="git add -A"
alias gd="git diff"
alias gb="git branch"
alias gx="git checkout"
__git_complete gx _git_checkout
alias gs="git status"
alias gl="git log" alias gcane="git commit --amend --no-edit" function fixup() {
git commit --fixup=$1
}
function refixup() {
git rebase -i --autosquash --autostash $1^1
}alias _up='sudo apt update -y && sudo apt upgrade -y'
Also not afraid to add multi-letter aliases if I find myself typing the same multi-word command over and over.
For example git diff master HEAD becomes gdmh
And then define one and two letter aliases for the things you do often:
st=status
l=log --with-prettiness
ap=add --patch
shit=reset
co=checkout
Command ' grep' not found, but there are 17 similar ones. Maybe I'm not the only one :).
doesn't expose you to typed functional programming (the ML school) though.
- bash + GNU coreutils; seriously, take the time to be able to write helpful bash scripts which can run basically anywhere.
- git; use it even when you're not pushing to a remote. Add helpful aliases for everyday commands. Build a good mental model of commits and branches to help you through tough merges. ( my ~/.gitconfig: https://gist.github.com/jeaye/950300ff8120950814879a46b796b3... )
- Regex; combined with bash and your GNU tools, a lot can be done.
- Vim; modal editing and vi-like navigation can blow open your mind. Explore the existing plugins to accomplish everything you want to be able to do. It's all there. ( my ~/.vimrc: https://github.com/jeaye/vimrc )
- Functional programming; if you're new to this, start with Clojure, not one of the less-practical languages. This has made such a huge impact on the way I think about code, write code, and design code that it's possibly the biggest one here for me.