I hear they are good, make it easier to maintain code-bases. Most often I reach for python to get the job done. Does anyone have experiences with functional languages for larger projects?

In particular I am interested to learn more on how to handle databases, and writing to them and what patterns they come up with. Is a database handle you can write to not … basically mutable state, the arch-nemesis of functional languages?

Are functional languages only useful with an imperative shell?

  • DNEAVES@lemmy.world
    link
    fedilink
    arrow-up
    5
    ·
    18 hours ago

    To answer the headline: Functional languages are as useful in pretty much any context non-functional ones are, they just need to be handled a little different.

    Functional languages’ goal tend to lean towards static or predictable typing and reduction of clandestine mutable state changes. State has to change in a program, it’s just about how its handled, and this is more about reducing referential update behavior.

    Like in Python, you can have a list, pass that to a function that returns None, but deep inside that function appends to the list, and you may be surprised that your list is different as a result. This would (typically) not happen in an FP language, you would have to explicitly return the changed list up the stack of functions, and as a dev you could see from a glance that the list could change as a result of the function, leading to less surprises.

    “IO” is of course an outlier, as it’s leaving the safety bubble the language provided. I could read the same database row twice in 60 seconds and get a different result, because someone else could make a transaction in that time. But once I have read the row and parsed it into a data-model, I can expect that my model in-code won’t change unless I tell it to.

  • whotookkarl@lemmy.dbzer0.com
    link
    fedilink
    arrow-up
    3
    ·
    17 hours ago

    It’s good to have some experience with them even just to know what tools may work best for a situation. I’d suggest something close to what you already know, C# -> F#, java -> clojure or scala, declaritive -> ML or Haskell, etc. dynamic vs static and strong vs weak typing systems can have a big impact on how you think about programs. Debuggers vs REPLs vs compiler warnings vs generic logs are all going to be different too on top of the paradigm like functional that will have different approaches. Minimizing the other differences makes it easier to focus on and learn the functional stuff.

    If you look at samples of a bunch and none are clicking I’d start with any that has dynamic typing, REPL style like common lisp, scheme, elixir. They are simple to get started with coming from python dynamic typing and options for interpreter & compiled, and you can add dependency management and interop and other stuff on top later. RDMS SQL is generally a static typed, declaritive style language. If you want a similar functional language look at ML, Haskell. But even in functional languages you’ll usually use a library or driver or language feature specifically for interacting with RDMS, you may use pandas in python and datomic in clojure.

    The big things to focus on are understanding common idioms like combining functions in call chains using basic functions map, reduce, & filter, etc, creating new objects with charges instead of changing in place (non mutable), and higher order functions/function composition that lack of mutability restriction allows.

  • darklamer@lemmy.dbzer0.com
    link
    fedilink
    arrow-up
    28
    ·
    1 day ago

    “Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot.” — Eric S. Raymond, How to Become a Hacker

    There’s definitely some truth behind the hyperbole in that quote and there are quite a lot of techniques from functional programming that can be used also in a language like Python with good results, when used judiciously.

    • Kacarott@aussie.zone
      link
      fedilink
      arrow-up
      15
      ·
      1 day ago

      I highly agree with the sentiment. Learning languages of different paradigms is sort of like travelling to visit other cultures to make you a more rounded, better person. Learn a functional language (lisp/Haskell). Learn a concatenative language (forth/Factor). Learn a logical language (Prolog/?). Heck even learn an assembly! (I suggest RISC-V).

  • masterspace@lemmy.ca
    link
    fedilink
    English
    arrow-up
    14
    ·
    edit-2
    1 day ago

    Most major languages these days are multi-paradigm languages that can do procedural, functional, or object oriented coding.

    C#, Kotlin, JavaScript, TypeScript, Go, Python, Swift, etc all fall into this bucket.

    Java has made a lot of efforts to support functional programming, but it’s still not first class.

    I would argue that these languages adopting functional coding as a first class citizen has made dedicated functional languages somewhat more obsolete, but they also paved the way and set the standards for the general languages that came after.

    On the web side of things, the most popular JavaScript / TypeScript frameworks these days are often fundamentally functional though, from React on the front-end to Express on the back end.

  • Oinks@lemmy.blahaj.zone
    link
    fedilink
    arrow-up
    6
    ·
    edit-2
    1 day ago

    Is a database handle you can write to not … basically mutable state, the arch-nemesis of functional languages?

    Well, kind of. You would treat it the same way you would treat pipe/terminal or file IO: You write some impure functions that do the actual IO (database calls), and some pure functions that work on your data types. Then you compose them together to make an application. Hopefully most of your code is in the pure part which means you can test it without having to mock the world.

    This honestly isn’t all that different from how a well written imperative code bases turn out. You generally don’t want to put all of the IO and all of the business logic into one super function or method or even class, because that makes things really hard to test (and hard to reason about too if you go far enough).

    You can have actual in-memory mutable state in functional programming too, you just don’t get it on every variable by default. At least in Haskell you would usually achieve this by using a type that does it for you, like IORef or ST or MVar or TVar. The reasoning above applies to those - You would generally use them sparingly, when you really need mutability (e.g. to pass data between threads), and not everywhere.

  • FishFace@piefed.social
    link
    fedilink
    English
    arrow-up
    6
    ·
    1 day ago

    Functional programming languages can be extremely beautiful when doing a task suited to them, but extremely ugly and cumbersome when doing anything not suited.

    With an imperative language you can always fall back on C-style for loops and manipulating state. It may not be beautiful but it’s fine. But if you need to use an STArray in Haskell, every single access is through a verbose function call without even array access syntax.

    So I would suggest either finding a toy project to do in a pure functional language, or else use a mixed paradigm language and make maximum use of its functional features.

    On databases, yeah database access is by definition stateful. It can be encapsulated in a monad, but that just means it’s not a good fit for pure functional programming.

  • subversive_dev@lemmy.ml
    link
    fedilink
    English
    arrow-up
    11
    ·
    edit-2
    1 day ago

    Got to put my plug in for Elixir. Built on the legendary Erlang runtime, looks like Ruby and secretly a Lisp under the covers. The Ecto database library blows every other ORM or tool I have ever used out of the water.

    Regarding mutability, I would argue the runtime has everything you need like message passing, software transactional memory, pleasant I/O and the best exception handling you could imagine

    • cv_octavio@piefed.ca
      link
      fedilink
      English
      arrow-up
      3
      ·
      1 day ago

      Seconding Elixir as a delightful and highly effective tool to solve almost every issue I’ve had.

  • jimmy90@lemmy.world
    link
    fedilink
    arrow-up
    4
    ·
    1 day ago

    they can do some clever stuff with composition but have never really caught on because they become hard to reason about very quickly

    as someone else mentioned, imperative languages have promoted the useful functional stuff so that it’s in common usage

  • ZILtoid1991@lemmy.world
    link
    fedilink
    arrow-up
    3
    ·
    1 day ago

    I prefer multi-paradigm languages with opt-in FP features, as purely FP languages can overcomplicate stuff, especially optimizations.

  • movies@lemmy.world
    link
    fedilink
    arrow-up
    6
    ·
    1 day ago

    Not at all. Plenty of functional services run at scale at multinational companies. I personally prefer them over OOP.

    What’s so special about database access? You pull data out. You transform it. You put data in. It’s just functions all the way down!

      • masterspace@lemmy.ca
        link
        fedilink
        English
        arrow-up
        9
        ·
        edit-2
        1 day ago

        Functional languages are inherently built on non-functional ones, for the same reason that object oriented languages are built on non object oriented ones, because cpus are fundamentally not object oriented or functional.

        They are computational machines with specific instructions around moving values in memory and performing certain operations on them.

        Assembly / machine code is always, at a fundamental level, imperative programming, and all higher ordered languages have to translate to these imperative instruction sets / languages.

        However, there is an OS that tries to be functional as much as possible though, and that’s a Linux distribution called NixOS, based on the functional language Nix.

      • Kacarott@aussie.zone
        link
        fedilink
        arrow-up
        5
        arrow-down
        1
        ·
        1 day ago

        A few good reasons, the first being that brand new operating systems don’t get written all that often. But even if they were, functional languages focus a lot on abstractions, making them generally higher level languages and so not fast enough to compete with C.

        Having said that, Rust’s design is quite inspired by functional languages in many ways, and it is indeed being used in operating systems.

      • litchralee@sh.itjust.works
        link
        fedilink
        English
        arrow-up
        2
        ·
        1 day ago

        There can be, although some parts may still need to be written in assembly (which is imperative, because that’s ultimately what most CPUs do), for parts like a kernel’s context switching logic. But C has similar restrictions, like how it is impossible to start a C function without initializing the stack. Exception: some CPUs (eg Cortex M) have a specialized mechanism to initialize the stack.

        As for why C, it’s a low-level language that maps well to most CPU’s native assembly language. If instead we had stack-based CPUs – eg Lisp Machines or a real Java Machine – then we’d probably be using other languages to write an OS for those systems.

  • TehPers@beehaw.org
    link
    fedilink
    English
    arrow-up
    3
    ·
    1 day ago

    Is a database handle you can write to not … basically mutable state, the arch-nemesis of functional languages?

    Access to an external database is a kind of effect. In functional terms, you’d use a monad to represent this, though in Koka you’d define an effect for it. In either case, it becomes part of the function signature.

    A “pure” function could instead work around it by returning (without executing) a query, accepting a state and returning a new, modified state, or otherwise returning some kind of commands to the caller without directly querying the database.

    • Oinks@lemmy.blahaj.zone
      link
      fedilink
      arrow-up
      3
      ·
      edit-2
      19 hours ago

      A “pure” function could instead work around it by returning (without executing) a query, accepting a state and returning a new, modified state, or otherwise returning some kind of commands to the caller without directly querying the database.

      At least in Haskell due to lazyness this is (almost) always what happens. A monad is just one kind of deferred computation, with an operator >>= (“bind”) that happens to prevent compiler reordering or deduplication. Any IO actions are only executed when main is evaluated and no earlier. Strict functional languages to my knowledge don’t need monads to do IO since they don’t have the same issues with evaluation order that Haskell does (though they might want them for type safety purposes).

  • sobchak@programming.dev
    link
    fedilink
    arrow-up
    2
    ·
    1 day ago

    I have not personally worked on large projects using functional languages. I know they are popular in finance/trading.

  • MagicShel@lemmy.zip
    link
    fedilink
    English
    arrow-up
    2
    ·
    1 day ago

    Closest I’ve actually used is Kotlin, but honestly I’d rather use functional paradigms within Java instead.

    I’ve watched a lot of videos on Haskell and Scala, and I think understanding what they are doing and why can only make you a better programmer.

    I use the Java functional package all the time. Understanding how to compose functions and define the input type and output type (either of which could be functions) is sort of awakening. Programming by side effect like with a method void doStuffWith(Foo foo) stands out as red flag if you are familiar with FP, but evidently it looks perfectly fine to someone exclusively familiar with OOP.

    That all being said, I don’t think FP is clearly superior. If you go all in, I suspect you’ll find yourself running into familiar problems wrapped in unfamiliar shapes. I think a very happy medium is to define data classes with only getters and setters instead of rich objects. Business logic can then be moved out to some handler, controller, or operand classes that operate on interfaces which the data objects implement.

    Mostly, FP forces you to think about some hard things and deliberately implement them instead of seeing what the default behavior is and fighting it when you don’t want it.

  • tiredofsametab@fedia.io
    link
    fedilink
    arrow-up
    2
    ·
    1 day ago

    I mostly work in Go, but I helped maintain one project written in Elixir for a while. It was rather interesting. It’s certainly a different way of thinking. It does reduce the risk of certain side effects but, as with everything, it has its own downsides.