lets talk Functional Programming. Is haskell based? What are some use cases? I really want to get into FP, but not sure where to start, between Haskell, OCaml, Elixir which would you pick?
Ape Out Shirt $21.68 |
lets talk Functional Programming. Is haskell based? What are some use cases? I really want to get into FP, but not sure where to start, between Haskell, OCaml, Elixir which would you pick?
Ape Out Shirt $21.68 |
https://learnyouahaskell.com/
I know the basics of haskell, but I want to dive deeper, or take up another FP language
>Is haskell based?
>I know the basics
gooh gooh ga ga
using an aryan here promotes harmful racial stereotypes
gem
what's the point of this when you have chatgpt?
Shouldn't you be asking chatGPT, stupid homosexual?
Wowowowoe! Tutorial in pure html, I am getting wet innere
Apparently GHCJS is still not ready for the real world.
https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html
Elixir is an oddball. It's "pragmatically" functional and I like it more for the BEAM and its macro system. I think it's the future but it doesn't scratch the same itch that something like Haskell does
Elixir is just ruby syntax applied to BEAM which is an actor programming framework (with built in networking). If your problem is best solved with actors, its awesome. But you also have AKKA and AKKA.net that solves the same problems, maybe not as elegantly as Elixir/BEAM, but close enough.
Actor pattern is how you scale to discord or twitter like demand.
Its OCaml for .net framework. Its so good C# design team copies everything F# team does in an awkward and incomplete way. Most C# programmers are clueless to this.
Its pretty successful, although in its finance niche. Its far more elegant and less verbose than C#. C# is the pajeet choice after Java. F# is the enlightened choice in .net ecosystem, but you will be alone.
> It's not as "pure" as Haskell.
Not its not, which is why I like it. Haskell is so fricking pedantic it feels like it was designed for proof of concept academic projects.
Good luck finding a job in that dead lang.
Oh definitely, I cram it into every company I work in like a serial internal git rapist. Usually on some crucial but one off project that they have to use but can't understand the code of. good luck firing me.
Pandoc and hledger are two beautiful softwares written in haskell. I can't name anything written in the other two.
Discord is mostly written in elixir
Idk what ocaml is used for other than Jane Street
Compilers.
Discord uses Elixir and Rust for the performance critical stuff, they originally used GO but switched to Rust because of the GC.
If you like static typing, try getting started with Haskell or OCaml. See which works better for you
If you like dynamic typing, try elixir if you're comfortable with lua or ruby, Erlang if you're a based boomer or Clojure if you like lisp
That's it, Godspeed anon
Where does F# fit into all of this?
The result of Microsoft unsuccessfully trying to abduct and rape fp enthusiasts. The only reason to use it is if your job is mandating .net everywhere but gives you enough flexibility to use something other than C#. Hardly anyone uses it.
The other reason is if you like OCaml, but want a usable std and ecosystem.
its good, have a look at typeproviders for something that may be unique to the language. I used the Fake build system for my C# projects build / deploy toolchains and it worked out really nicely. I'm a fan of F# but haven't used it for anything significant so far.
It is based as frick.
Because it is.
Extremely well designed -- they've thought of ~everything without complicating too much (like Scala, which tried everything and failed)
Long-term evolution: it's been around for decades and has evolved organically
Beautiful, clear syntax
Makes writing "correct" code easy
Surprisingly fast and performant
For those who think in Types, it gives you very strong tools
Somewhat hard to pick up, so appeals to the intelligentsia and the morons on IQfy
As someone with double digit iq and questionable skin color I can confirm that Haskell appeals to morons.
> Extremely well designed
This language has 3 types of strings and around 5 alternative standard libraries because standart one is so shit everyone wants to create their own. Haskell is as well designed as js when it comes to libraries
> Long-term evolution: it's been around for decades and has evolved organically
It doesn't work properly anywhere except x64 Linux and require some library for anything, even dates, jsons and collections
In haskell, only it's language specification is great. Everything else is so shit you can't use it for anything except cli apps and compilers
> Surprisingly fast and performant
Only when you know language very well and able to see what code under all these abstractions and lazy evaluation are doing. And in reality any performant code would look like ugly non idiomatic mess
String = [Char]
Lol.
Also, originally Monad was not a superclass of Applicative because it came first.
It indeed has a lot of issues with it. Rust also seemed super clean at the start because it could learn from many of the mistakes of other languages but the warts are starting to show.
go cold turkey with haskell. with other choices, you get the tempation of using mutable state as a crutch and thus failing to learn what you sought to learn
there's also Text and Bytestring, and 2 variants of each. That being said, it's only really an issue when you have to use qualified names everywhere. I hate that shit
I more so mean that “String = [Char]” was a terrible decision, those 32-biye chars are boxed by the way.
A linked list of 32-byte chars, all of them on the heap, to encode a string.
There's a good reason other functional languages such as Scheme and OCaml never did that but if you ask me String should be a typeclass, not a type which they did do for numbers so it's weird. Then again, I'm not sure why Haskell doesn't have a general Sequence typeclass either. It's obviously easy to define but there are many standard library functions that demand a list in particular that could work fine with any abstract sequence.
Strings as linked list is a terrible decision, but as said, make it a type class and give them both as lists or as constant time vectors.
It's a tug of war between pragmatists and autists.
>I'm not sure why Haskell doesn't have a general Sequence typeclass either.
There's lists, functors, foldable and traversable.
to be fair, some "looser" versions of polymorphic sequences can already be approximated through existing typeclasses. Traversable and MonadPlus should let you do a lot of the things you want to do with sequences.
monadic bang is neat for small examples but is also counterintuitive. for example:
setRef x "40" >> print !(readRef x)
doesn't do what you might think
clojure is cool but frankly it's stupid in a lot of ways
>clojure is cool but frankly it's stupid in a lot of ways
It has a few rough edges I agree, but it's great for people like me who suck at remembering syntax
The "right" order isn't a consequence of the simple rule: do !(!mma) !mb = do ma <- mma; b <- mb; !ma b
We could transform the `>>` into `;` first.
With Ghc-8.4 LSP understood monadic bang until I split my project into multiple files. The newest GHC/LSP has no problems.
Did you try Control.Monad.Cont? I don't use it because mapMaybe or other functions from base and lens don't leave me reaching for deeply nested loops with break.
>he wants use cases
Scala
Yes, it's the least pure of the FP languages, but there is more shit build in it than the others (except Erlang but you're not 50 years old)
>except Erlang but you're not 50 years old
Elixir can call any erlang module with technically 0 friction and is syntactically similar to ruby.
Discord, plenty of others. FP features have been bundled into every corpolang and are now the default way to do certain things (LINQ and lambdas are fricking everywhere in C#).
Elixir is still typeless (until next year)
Right now if you want to do FP productively, unironically I recommend either Scala or Clojure.
Haskell is cool. Haskell programmers are ALL smug amateurs.
haskell is worth trying as a learning language, I don't think I'd like it for writing serious programs though.
Has there been a single relevant program made using a functional language? If so what one?
https://github.com/apache/spark
>it's not all pure FP
Yeah, pragmatism wins
Telecoms software.
Big data processing systems.
Media streaming services.
crash bandicoot is one.
for haskell specifically:
GHC
plutus (for the cardano blockchain)
pandoc
xmonad
criterion (software benchmarking suite)
hedgewars: the server is written in haskell
copilot
there's also software used by companies (such as facebook, mercury, standard chartered, groq) and lots of unshared software (such as a few tools I wrote for myself in haskell)
I don't have enough RAM to run a Haskell Hello World.
Also, F# is cool. It's like OCaml but with the ,NET ecosystem and pretty decent tooling. It's not as "pure" as Haskell.
In practice, non-strict languages weren't worth it I'd say.
Idris is also strict though purely functional.
I don't get this overcomplicated “monad” shit though. Like, is there any real harm in:
>Language type system has a distinction between pure and impure functions
>pure functions can only call other pure functions
>impure functions can call both pure and impure functions
>main is obviously an impure function
Like what am I missing? How is that not just as good and far simpler? Is it just so you can say “the language is purely functional” rather than “the type system discriminates between pure and impure functions” even though monads are nothing more than a type system hack that force the optimize to respect a certain sequence and under the hood PutStrLn : String -> IO () is actually just an impure function and “IO” is simply a container around a linear datatype.
At least Clean wasn't hiding what it was doing and simply returned the “world” type.
>Language type system has a distinction between pure and impure functions
>pure functions can only call other pure functions
>impure functions can call both pure and impure functions
>main is obviously an impure function
homie you can do all that in C23 with [[u sequenced]] and [[reproducible]]
And in any C standard with GCC/clang attributes pure/const
That ain't functional programming
He was complaining about monads fricking the type system and proposing this instead. I agree with him. The only good thing I can see in monads is not needing explicit error handling (if an error occures in any step in your error monad it is returned by the function)
You didn't answer what the effective difference in provability and the benefits of referential transparency was.
All this has nothing to do with whether monads are used instead of a simple pure/impure distinction. It can exist independently of that.
I didn't even mention do-notaation which is purely syntactic sugar.
The point is get GetLine >>= PutStrLn under the hood simply calls two unpure functions. What actually more or less happens is that two impure functions exist:
GetLine# :: World -> (String, World)
PutStrLn# :: (String, World) -> World
Where “world” is essentially a virtual datum that does nothing, every impure function accepts a “World” argument and returns one. Since they all depend on the World argument returned by the last, the graph reduction algorithm must execute them in sequence. That's what >>= effectively does behind the screens, it unpacks that World argument and feeds it to the next function.
Monads are simply one giant hack that abstract away a Uniqueness type like Clean has that is never exposed to the user and the IO Monad, which can't be used defined and is simply part of the language handles it behind the screens and ensures that it stay unique.
Clean works similarly except it makes this visible and requires the programmer to explicitly pass this dummy value around and the type system enforces the constraint upon it that it be Unique which is Clean's way of saying “linear type” but at least it doesn't hide that these functions are basically impure functions wrangled into a type system that acts like they aren't.
It feels like it mostly exists to say “all our functions are pure”, not to give any greater provability or ability to reason over code.
>one giant hack
You repeating this doesn't make it so. Monads are super simple and easy to understand, and I genuinely don't get why you seem to be so against them. Do you even program in Haskell, or just talk about it?
Your proposed solution of passing around a World value was tried before, and it just makes things inconvenient for no good reason. It requires the programmer to pass around values, and people would have to reinvent do-like syntactic sugar anyway to make things convenient. I don't understand why you want to do this.
I didn't mention this because I thought it's pretty obvious why this isn't done. Impure functions interact extremely poorly with lazy evaluation, and break referential transparency. So you'd have to get rid of the two things that make Haskell Haskell. If you want that, you already have Kotlin (not an insult, Kotlin is actually nice to program in).
Also, how would it be "far simpler"? Monads are already very simple. You're proposing solutions to imaginary problems.
And you never addressed that monads are a lot more general than just a system to mark things pure or impure. For example, once you have something like do notation, it can be reused for parsers, async computations, or probabilistic computations.
If you need a beginner Haskell book, I recommend the purple one.
>You repeating this doesn't make it so. Monads are super simple and easy to understand, and I genuinely don't get why you seem to be so against them. Do you even program in Haskell, or just talk about it?
>Your proposed solution of passing around a World value was tried before, and it just makes things inconvenient for no good reason. It requires the programmer to pass around values, and people would have to reinvent do-like syntactic sugar anyway to make things convenient. I don't understand why you want to do this.
It isn't my proposed solution. Read.
I simply said it abstracts that away and does it behind the screens and that these functions aren't pure at all but the hack is hidden from the user by use of Monads.
My solution is what Koka indeed does. Simply partition the language into pure and impure functions on a type system level and that's it.
Monads are incredibly overengineered to abstract away effects and on top of that annoying to program in and often read to purely readable code, that's why Do-notation was invented because without it, code would quickly become unreasonable and even with it it's not pretty.
>I didn't mention this because I thought it's pretty obvious why this isn't done. Impure functions interact extremely poorly with lazy evaluation, and break referential transparency. So you'd have to get rid of the two things that make Haskell Haskell. If you want that, you already have Kotlin (not an insult, Kotlin is actually nice to program in).
It's pretty easy to make all impure functions strict and make no such condition apply to impure functions.
But Idris is strict and still uses this IO Monad thing for effects. That's simply weird.
Also, many impure languages use call by name. Algol already did it. It's quite easy to make Haskell so that even impure functions are called by name, which can of course become call-by-need for any pure functions.
>But Idris is strict and still uses this IO Monad thing for effects. That's simply weird.
It's not weird. Monads are the most elegant way to handle side effects if you want a language that's lazy and/or referentially transparent. The Monad typeclass can be defined in just a few lines of code, and if you add a bit of syntactic sugar, you get a very general abstraction for things that can be sequenced together: I/O operations, parsers, async operations in coroutines, probabilistic computations, etc. Monads are so simple that anyone smart can understand them in 15 minutes, and so useful that people who come from Haskell often miss them in C# or Scala, and want to reinvent them. I find your insistence that they're complicated, difficult, and overengineered is ridiculous. You should go read a beginner Haskell book instead of inventing imaginary problems to justify things you don't understand.
Anon, no, all of that can be done in a far simpler way by simply letting the type of the function dictate whether it can have effects or not.
Everyone understands monads, everyone understands GOTOs as well. Code written with monads quickly becomes completely unreadable without do-notation so that needed to be added at well and at that point what you're left with is simply the same syntax as in an imperative language, but less expressive.
>people who come from Haskell often miss them in C# or Scala
how are they missing in Scala?
Idk the exact definition and I don't care, but Option and Try work for all the use cases your cited. Using for comprehensions instead of do notation. Not that I use them cause you get 90% of the benefits of FP using map/filter/reduce and pattern matching...
Result-like types are also a monad by the way, that's why Either and Just in Haskell are also in that type class.
Rust syntax with the carrier trait is a lot more convenient though, and Rust's type system can't fully express monads due to the lack of higher-kinded traits.
But no, monads to trick the type system into believing that impure functions are actually pure without all the disasters the optimizer would do is asinine and overengineered. Simply admit that they aren't pure and be done with that.
It's a hack like Uniqueness types except it's even more abstracted away. It is literally just secretly handling a Uniqueness type behind the screens and having impure functions without owing up to it, which is IO a is magical and special. It can't actually be defined by the user because it'a a special compiler hack to act like impure functions aren't pure.
If it were so elegant one would be able to define it oneself and write one's own Monad IO implementation, but one can't; it simply exists.
>Option and Try
>for comprehensions instead of do notation
Congratulations, you just reinvented them with slightly different syntax
>Idk the exact definition and I don't care
Why argue about things you don't understand? You could just google the definition. I swear, the people on this website are getting more moronic by the year.
Okay, so add do notation. What's the problem again? It seems that you really dislike monads but can't formulate any sensible argument against them, you just parrot that they're "overcomplicated" and other methods are "far simpler", which is obviously not true - monads are simultaneously simple and general, and I already pointed out that you can't have impure functions if you want your language to be lazy and/or referentially transparent.
Yes, you stated that, and I pointed out that you were wrong and even Algol, which was not referentially transparent also had call-by-name semantics.
Anon, if you actually believe that monads are simpler than simply having impure functions you're insane. The fact that they needed to add do-notation, which again is less flexible shows this.
Something extremely basic like like an infinite loop that keeps on running and handles events is, even with do-notation, not that clean in Haskell. You have to create some kind of temporary binding and have the function call itself. You're crazy if you think that
main = loop
where loop = do
<CODE GOES HERE>
loop
Is somehow not a convoluted solution for what could be:
loop {
<CODE GOES HERE>
}
do-notation only solves the most trivial of cases
Next up is breaking from a loop based on a condition using do-notation which quickly becomes a hack of injecting (), now try breaking from a nested loop...
Monads aren't problematic. Using them for side-effects is. It's an overengineered solution that quickly results into hard to read code that was simply only invented to be able to say “our language is purely functional, every function is pure”, even though it's really only true as on the type level.
And on top of that, as I said, it's magical. One can't write the IO Monad oneself as a library function as one can write the Maybe Monad or the Either Monad or the List Monad. It's magic provided by the runtime.
Those are all not really sequences though.
What I mean is something that has a length and an index operation within that length. Probably also things such as appending and slicing.
monads also generalize to things like choice (lists as a monad), failure (maybe / either as a monad), and so on.
btw your example is moronic. you could just write
main = forever $ <CODE GOES HERE>
with forever being either imported or written as a one-liner such as
forever m = m' where m' = m *> m'
you can also import or define lots of other constructs as convenient.
scala is irrelevant doe. it's also the troony of programming languages, as it's basically java pretending to be something like haskell. any decent haskeller can sense that there's something wrong with scala, and you can find several write-ups (for example, one from edward kmett) articulating this.
>monads also generalize to things like choice (lists as a monad), failure (maybe / either as a monad), and so on.
Which has nothing to do with and isn't used for side effects.
Note that all those things can be implemented as library functions while Monad IO is magical.
>btw your example is moronic. you could just write
That only works if the entire main be the body of the loop which almost never happens and it certainly doesn't solve breaking from or returning a value from a loop.
>you can also import or define lots of other constructs as convenient.
You can, and it turns code unreadable very quickly.
Please, write this utterly simple logic in the IO Monad:
loop
putStr "Please enter your name: "
name <- getLine ()
if name == "John" then
break
else
putStrLn "Your name is wrong, let's try again."
Obviously it's easy to write it, but it will look convoluted, messy, and hard to parse.
import System.IO
main = askName
where
askName = do
putStr "Please enter your name: "
hFlush stdout
name <- getLine
if name == "John" then
return name
else do
putStrLn "Your name is wrong, let's try again."
askName
Replace putStr for putStrLn if you don't want to flush buffer.
Yes, there you go, random “where” clause has to be made temporary binding, for what reason?
Now imagine breaking from a nested loop. It becomes unnecessarily messy very quickly for no good reason.
main = do
name <- let loop1 = do
putStrLn "Name?"
n <- getLine
if n == "John" then
let loop2 = do
putStrLn "Surname?"
s <- getLine
if s == "Doe" then
return (n ++ " " ++ s)
else do
putStrLn "Wrong (nested)."
loop2
in loop2
else do
putStrLn "Wrong"
loop1
in loop1
putStrLn ("Hello " ++ name)
import Control.Monad.Cont
import Control.Monad.IO.Class
import Control.Monad
main = do
let q prompt = liftIO $ do
putStrLn prompt
getLine
p = liftIO . putStrLn
name <- runContT `flip` return $ callCC $ exit -> forever $ do
n <- q "Name"
if n == "John"
then forever $ do
s <- q "Surname?"
if s == "Doe"
then exit (n ++ " " ++ s)
else p "Wrong (nested)."
else p "Wrong"
putStrLn ("Hello " ++ name)
And would you not agree that this is beyond unreadable compared to a simple nested break from a loop?
This is why Monads for effects are a bad idea.
What even is this code opposed to a simple labeled outer loop and a break to it. Even without labeled loops, checking a value to decide to break is much more readable than this monstrosity.
But it is labeled outer loop and a break to it. Instead of "label : do {" it's "callCC $ label -> forever $ do". Instead of "break label" it's "label ()". The noise from liftIO, runContT `flip` return and some of the $ is unfortunate but it's not enough to be "unreadable".
Python can't 'break' from a nested function, so you there are more cases where you can't take a chunk of code in a loop and give a name and restrict scope. If an inner loop is a .map you can't write it as such because "while/break" wasn't designed right. Pythonic is the sour grapes cope.
You can do my simple loop1-loop2 solution for readability like other languages or use the Cont monad which is a nuclear bomb to solve it (it solves problems beyond loops, like modeling functions that work with a ton of callbacks)
Too bad lazy IO doesn't scale
import System.IO.Unsafe
inputLines = do
x <- unsafeInterleaveIO getLine
xs <- unsafeInterleaveIO inputLines
return (x:xs)
main = do
ls <- inputLines
process 0 ls
process :: Int -> [String] -> IO ()
process n stack = do
case n of
0 -> putStrLn "Name?"
1 -> putStrLn "Surname?"
case (stack, n) of
("John" : rest, _) -> do
process 1 rest
("Doe" : rest, _) -> do
putStrLn "Hello John Doe!"
process 0 rest
(_:rest, 0) -> do
putStrLn "Wrong"
process 0 rest
(_:rest, 1) -> do
putStrLn "Wrong (nested)."
process 1 rest
>unsafeInterleaveIO
delete this
Proper LinearTypes multiplicity polymorphism when?
a lot of imperative languages don't support breaking out of nested loops either :). probably for good reason, too. most nested loops are better done by having a single loop with the combined iterators from the two loops it replaces. other use cases would have to be judged separately to decide whether nested break would be readable
btw
is dunking on you for fun
I'm guessing that name isn't meant to be scoped in the loop. just do
name <- untilJust $ do
t <- getLine
pure (if t then Just t else putStrLn "Your name is wrong, lets try again" $> Nothing)
...
untilJust m = n where
n = do
x <- m
case x of
Just a -> pure a
Nothing -> m
this could be less verbose, but this way you can make sense of it. you could also just search
Monad m => m (Maybe a) -> m a
in Hoogle to find an implementation of untilJust and import it.
by "you" in "this way you can make sense of it", I mean someone with basically zero haskell experience.
Lmao Haskell cope. Scala is the only FP lang with a decent amount of Jobs out there. You can't find a single large enterprise that isn't using it somewhere. Even Apple has plenty of open Scala positions. Keep coping with your autistic language that no one uses. Pure FP is moronic.
If you’re evaluating languages by jobs, stick to Python, JavaScript, and the POO languages.
>I don't get this overcomplicated “monad” shit though. Like, is there any real harm in:
I suggest you check out effect systems. They can solve many of the same problems of monads, but without the ivory tower feeling.
There are more stuff that you expect from a foonctional lang
some support for recursion optimization. Admittedly even C has it in a very basic form with attribute musttail
Some way to do higher-order functions that doesn't SUCK. (function pointers fricking SUCK because they never inline)
Algebraic data types
Strong type systems in general, shit like covariance/contravariance is hard to do without once you've tasted it
Some form of generic because you can't go very far with void pointers
And in general, I'd say functional languages are more about what you can't do than what you can do. The more pure your computation graph is, the more your compiler can do its thing, so enforcement matters. You kinda want to be able to force coding in a way such that the next imperative brained dude who touches your code doesn't destroy your beautiful computation graph.
So yeah, there's more to FP than "imperative, but lots of pure functions"
>overcomplicated “monad”
How do you not get something this basic despite knowing about so many functional programming languages? Do you just write a hello world in each of them and then move on to the next?
Because they're moronic larpers
I broadly agree with you on Haskell but the ocaml ecosystem seems dismal
Yep. The Jane Street style ecosystem is good but very small. I don't really like OCaml syntax either. But OP didn't give many options, and I'd pick OCaml over Haskell because the Haskell standard library situation is so frustrating.
What? You don't have to use do-notation to use a monad. You can just do something like
main = putStrLn "Hello, world"
Your stream alternative has been tried in the past and was far worse, as was passing around a "world" type.
I seem to have stepped into some kind of Dunning-Kruger thread. Only total beginners who can't program in Haskell think that monads are difficult or complicated. It's like reading these morons on Reddit who complain about Python's indentation or __main__, as if these "problems" weren't insignificant.
Also, I never mentioned “streams” either as in what Miranda does. You're arguing against ghosts.
I said that it's far simpler to simply have the type system discriminate between pure and impure functions and enforce a constraint that:
>impure functions can call both pure and impure functions
>pure functions can only call other pure functions
That's it. Nothing else is needed. No streams, no monads, no uniqueness types.
>You don't have to use do-notation to use a monad
You do if something you need to use is provided in a monad
x <- returnsMonad y
Were you projecting when you said we don't write anything more than hello world lol?
Have you met the monadic-bang gang?
>I seem to have stepped into some kind of Dunning-Kruger thread.
You are on G, after all
Personally I dislike the effects of monads in the type system. If you want to include in your function something which for whatever reason is provided in a monad, well you are forced to return a monad and thus do the imperative style do notation even though it doesn't have to be that way and your function could have been a one-liner if that stupid thing wasn't provided in a monad. There are alternatives to monads, you could use streams or infinite lists for user input, random numbers and a lot of other monads
>Monads == do-notation
Uh oh, moron alert!
See Koka for a good design of purity/impurity.
Koka also allows you to specify other function colors, such as async, total/diverging, throwing/noexcept.
Is it just typeclasses?
It's this thing where you declare an "effect" (=function color) and then label the functions that need that effect.
You can only call a colored function if either the calling function is also colored, or the function call is wrapped with an effect handler.
Examples from Koka book:
fun sqr : (int) -> total int // total: mathematical total function
fun divide : (int,int) -> exn int // exn: may raise an exception (partial)
fun turing : (tape) -> div int // div: may not terminate (diverge)
fun print : (string) -> console () // console: may write to the console
fun rand : () -> ndet int // ndet: non-deterministic
fun traverse( xs : list<int> ) : yield () // <-- colored with yield
match xs
Cons(x,xx) -> if yield(x) then traverse(xx) else ()
Nil -> ()
fun print-elems() : console () // <-- color allows calling println
with ctl yield(i) // <-- effect handler allows calling traverse
println("yielded " ++ i.show)
resume(i<=2)
traverse([1,2,3,4])
That seems like a much better system yes.
So you can have an effect handler for impure functions inside of pure functions? How that does not seem kosher right?
It works out nicely for mutable state that's contained within a single program, because the impurity can't escape outside the effect handler.
For example:
effect state<a> // declare color for mutable variable
fun get() : a
fun set( x : a ) : ()
fun sumdown( sum : int = 0 ) : <state<int>,div> int
val i = get()
if i <= 0 then sum else
set( i - 1 )
sumdown( sum + i )
fun state( init : a, action : () -> <state<a>,div|e> b ) : <div|e> b
var st := init
with handler
fun get() st
fun set(i) st := i
action()
fun main()
state(3){ sumdown() } // 6, state is contained in this call
state(10){ sumdown() } // 55, different state variable than before
External impurity like I/O is dangerous, yes. It's kind of like Rust's unsafe where the language holds your hand up to a point, but allows hiding impure I/O if you're naughty.
Generally, the idea is that everything requiring external impurity (e.g. I/O) is colored with the correct label and the effect handlers are near the main func.
The first shill in a long time to convince me to try something on IQfy (I'm not even sure you're a shill or just an autist)
That's so cool. Is the total/div checked by the compiler or deos it just trust the user?
The compiler checks div, or rather automatically infers most recursive functions to be div and adds the effect automatically. Unfortunately, this goes for most terminating functions too because the compiler isn't very good at recursion proofs.
Total is just a special name for absence of effects.
In practice, the user can leave most types and effects out because inference just werks.
>because the compiler isn't very good at recursion proofs.
It's the halting problem. The compiler literally cannot solve it. Do total functions recieve any beneftis?
Right, so that's just like cats effect's typeclasses innit?
>Perceus is an advanced compilation method for reference counting. Together with evidence passing, this lets Koka compile directly to C code without needing a garbage collector or runtime system. Perceus also performs reuse analysis and optimizes functional-style programs to use in-place updates when possible
I will now try your language
So what about this div thing? Does it do anything, like throw a warning if your main has div, or can you handle timeout policy somewhere in a centralized place or something?
>A warning if your man has div
Anon... if main couldn't be div the language wouldn't be during complete.
Sure, which is why I said a warning.
I mean, does div do anything apart from existing?
It's the opposite that's obviously interesting, that a function is total, which can't be decided but in reverse, if the compiler can prove it then we know that function is total and that that part of the code thus doesn't contain the bug we might be searching for.
It's useful to avoid bugs to move divergent computations to as few functions as possible, it's like asking:
>What good does it do knowing for sure that 99% of the functions in the language can't lead to undefined behavior, and only 1% can which are marked as such.
You know that when you get a segfault that the problem can't be in the 99%.
Thank you
main is not impure. what you're missing is that functions can define changes of state over time.
They can, but such functions aren't used here; they simply have side effects but the IO Monad is effectively having the type system enforce a continuation-passing-style discipline over using them, together with two layers of syntactic sugar that makes that style look like an imperative language again, in order to define a specific sequence of evaluation order over functions that, simply put, have side effects in a language that otherwise can't define sequencing.
But even in a non-strict language without a defined evaluation order, c.p.s. still defines one.
you just said in a complicated way, what i said in a simple way.
No, I said something completely different. What I said spoke of functions that have side effects not to mention that time and changes as well as state are irrelevant for what I said. Simply that functions are not referentialy transparent.
just because the side effects are modelled with functions doesn't mean they are not pure. side effects only matter at execution time. this is the part you are not understanding. you still think in C unfortunately.
Everything only matters at execution time, what even is that argument.
Let me put it like this, inside of the GHC IO source code it literally defines something like:
newtype IO a = IO (RealWorld# -> (RealWorld#, a)
That should tell you that anything of type IO a is really just an impure function hidden behind a newtype so it can't be called directly but what it fundamentally is is simply an impure function.
I bet you're the guy who was on here arguing that "monads" are just continuations (wrong). imagine thinking these things when the list monad exists. you don't want to learn anything or think differently.
No, I never said “monads” were anything. I said using monads to sequence impure functions in a language is the same as using c.p.s. to sequence them.
You can't read and think I have something against monads in general; I don't and think they're useful. I simply think using them to express sequencing of impure functions like that and a hack the same way uniqueness types to do the same is a hack.
There's a good reason that Eq a => Eq [a] is defined, but somehow Eq a => IO a is not. Because the former is not a hack and the latter is. One can already see that by the basic fact that the list monad is implemented in pure Haskell without requiring any compiler magic whereas the IO Monad requires special magical help from the compiler to implement and that one can't write one's own IO Monad and that it requires a magical RealWorld datatype internal to the compiler to work.
>a high level language interfacing with low level stuff has to do hacks to abstract it
POSIX is a hack, not raw dogging your assembly is a hack. Everything is a hack. UGLY.
I wouldn't call what Kota does a hack. Also has nothing to do with high or low level.
I'd call both Uniquess types and monads to sequence impure functions but claiming they're pure a hack though. What Kota does is transparent. It's open about that they are impure and treats them as such.
Uniqueness and monads are pure. Given the same computer state as input, and the computation continuation, the result will always be the same next state. The contents are impure, the state never repeats, the clock is always ticking, it may partially repeat and give similar results. Or maybe the PC gets hit by lightning and it gets fried and suffers the ultimate side effect and your square <total<int>> never returns.
>internally uses monads for effects
Ok.
>Uniqueness and monads are pure. Given the same computer state as input, and the computation continuation, the result will always be the same next state.
Yeah no, RealWorld in both cases doesn't change and is always the same datum.
This is entirely different from say a Unique array being mutated by a function that internally mutates it as an optimization which it knows it can perform due to the Unique type. Because it's purely an optimization and program semantics would be the same if it allocated a fresh new array and on top of that the difference can actually be observed because the array before and after can be analysed.
RealWorld is either a datatype hidden away from the user that can't be compared, or when it can, it's a unit type that remains the same throughout the program, and obviously program semantics would change completely if the side effect were to not happen. It's not merely an optimization.
The array mutating as an optimization is an implementation detail.
RealWorld can't be compared because it's abstract and it represents all the pointers and memory and all the runtime state of everything. The unit type represents that too. They could use an Int instead to represent a returned status code like C.
Clean's unique World is not just an optimization either, it enables optimizations and ensures purity.
>RealWorld can't be compared because it's abstract and it represents all the pointers and memory and all the runtime state of everything.
It doesn't. It gets deleted at the end of optimization by the compiler.
It's an entirely magical type that is a zero-sized type that is given magical treatment by the compiler such that:
>It is a zero-sized unit type so it's deleted entirely at the end
>But, unlike all other unit types, it does create data-dependencies.
This needs to be hardcoded into the compiler for the compilation process to work and the order of execution to be kept. If rule 2 did not apply it would order them out of sequence as an optimization. It doesn't “represent” anything in either language. It's a complete hack.
The unit type most certainly does not represent that. It's a zero-sized type that the compiler erases.
>pure Haskell without requiring any compiler magic whereas the IO Monad requires special magical help from the compiler to implement and that one can't write one's own IO Monad and that it requires a magical RealWorld datatype internal to the compiler to work.
well duh, this is what an abstraction is. I suggest you read some of the papers by wadler and peyton jones back in the early 90s. it's not a hack, the language itself is pure. real world things can be modelled with mathematics.
>well duh, this is what an abstraction is.
>Abstraction means special compiler magic.
No anon, the list, maybe, either and what-not monads are also abstractions but they can be written in Pure Haskell without requiring a special datatype that the optimizer treats like no other datatype to work.
>real world things can be modelled with mathematics.
And they're not modeling it, their “real world” is not a model; it's literally a unit type that's given special treatment by the compiler to only be erased at the end and still create data-dependencies. This is not a model of the “real world”. This is a way to sequence side effects by creating a fictive dependency that otherwise doesn't exist in a lazy language.
The “real world” here is modeled with side-effects.
Also, come to think of it, with machine random number generation from quantum uncertainties, which does exist, the “RealWorld” actually cannot model it any more. Referential transparency is truly lost there even in a hypothetical case where the entire state of the world were somehow stored into a datum, a ridiculous thing to begin with even without such true random number generation because even pseudo random number generation literally takes ambient air in the room the machine is standing on as input through temperature censors.
https://dl.acm.org/doi/pdf/10.1145/158511.158524
And it literally says:
>But what has become of’ the world values in the final
>C code? The world value manipulated by the program
>represents the current stat e of the real world, but since the
>real world is updated ‘(in ~Jace” the world value carries no
>useful information. Hence we simply arrange that no code
>is ever generated to move values of type World. This is
>easy to do, as type information is preserved throughout
>the compiler. In particular, the world is never loaded
>into a register, stored in ZL data structure, or passed to C
They're not doing the opposite of what you described. They're not modelling side effects by having a RealWorld datum, they're modeling a restricted form of RealWorld by having side effects.
RealWorld in the full form is strictly more powerful than mere side-effects because it can express storing and restarting states, examining the real world to see if the result be satisfactory, if not, then restart from a certain place and do it again to eventually arrive at the RealWorld one wants. This can't be done with RealWorld as an artifical uniqueness type where one can never get back to a prior state without having a function that could do so, and since all functions work with side effects, not with actually manipulating a RealWorld datum and one wan't unwrite lines to a terminal or undelete a file, such a function can't be made.
It's the opposite. It's not modeling side-effects with RealWorld, it's modeling a limited version of RealWorld with side effects.
>What do you mean I can't compare functions for equality?!
>thread is just a bunch of morons arguing about
welcome to IQfy, newbie
never heard of such a thing, but it's an interesting idea
you'd probably want some sort of flow based functionalish DSL for robotics though
Lisp was used for artificial intelligence and robotics in space with great success until C deposed it because the runtime was too fat.
More like:
>It makes sense for the Eq impementation to exist
>It's super simple to impement
>Doesn't exist, because if it were to exist, it would expose that IO a hid an impure function inside.
>It makes sense for the Eq impementation to exist
>It's super simple to implement
totally wrong. The only sensible equivalence relation is functional equality, which is undecidable.
Yes, in the general case, but not when the input domain of the function is finite, in this case, it's only one element as RealWorld only has one member.
Of course, with impure functions that all changes which is why it's impure, but with pure functions it's trivial to decide the identicality of Eq a => RealWorld -> (Realworld, a). Just do:
x == y = snd (x realWorld) == snd (y realWorld)
And that's it.
>distinction between pure and impure functions
Congratulations for reinventing the color problem. Enjoy the hell you have created.
What's the problem with it and why is it worse than monadic IO?
Putstrln is not impure thoughever
Calling it will never print a string and the IO is not a container around a tuple, the IO is more like a promise or future that will be fulfilled by the runtime (it is actually a closure that takes a Realworld dummy type and prints the string it closes over)
Although what you said about monads being a hack is kind of true, and some languages do actually have a differentiation between the arrow type for impure and pure functions
Between these, I'd pick OCaml and get into the Jane Street ecosystem.
If you want Haskell, then the purple book is better than LYAH. But I don't do Haskell anymore. The standard library is terrible, it doesn't even have a decent string type or a hashtable. And I'm not convinced that lazy evaluation is a good default. Monads are totally fine though, people who think they're difficult are just brainlets.
Any of you fooncbrains have experience with Futhark and Granule?
What's amazing about FP is you never know what they'll say.
Today, monads are only about side-effects, apparently.
Obviously not. I'm talking about abstracting effectful functions away in monads.
The reality is that a language can never truly be “pure” and be useful outside of purely computing a value at the end based on input without user interaction so they come with different ways to claim being “pure” while still allowing it, all of them ridiculous hacks.
I'm talking about the monad hack here, but the uniqueness type hack and the stream hack are hacks all the same.
I'm saying drop the hacks and just admit that it's an overconvoluted way to partition the language into pure and impure functions and fool the type system so that even though it treats impure functions as pure, it still can't sequence them out of order.
Simply on a type level discriminate between pure and impure functions and call it a day.
Anon, you don't need do-notation for that either which is purely syntactic sugar around “>>=”, “return” and ”>>”.
It will make your code more readable though.
>">>=”, “return” and ”>>”
I don't like those either because they look worse. Do notation forces you to not write point-free code. That's the main reason I dislike it
The reality is that a language can never truly be “pure” and be useful outside of purely computing a value at the end based on input without user interaction so they come with different ways to claim being “pure” while still allowing it, all of them ridiculous hacks.
>based on input without user interaction
what if function's input is a result of user interaction ?
recursion with a condition is functional too
elm. by the time you move onto haskell and learn what a monad is you'll realize you've already been using them
Learn Erlang
>not sure where to start
anon, try https://haskell.mooc.fi
best i found so far and it's free
course uses a haskell build system that just works
has assignments with auto-grading system. you clone their git repo and there's a framework to grade your answers automatically
thank you anon, this actually looks very interesting.
>between Haskell, OCaml, Elixir which would you pick?
Clojure
It's cringe. OOP is cringe too. Make code your focus and you're now a homosexual. Just get shit done until your employer gets in your way.
C is better
Scala is the only relevant FP language and since Scala 3 it's based af.
If you want to do pure FP use ZIO and if you simply want to get shit done use Haoyis libraries which are now part of Scala Toolkit.
Lisp
None of the above. I suggest either Idris or Lean4.
Scala
https://jobs.apple.com/en-us/search?search=Scala&sort=relevance&location=united-states-USA
Haskell:
https://jobs.apple.com/en-us/search?search=Haskell&sort=relevance&location=united-states-USA
Bfffhahahahahahahahhaha
DELETE this Odersky.
LMAO
No ones arguing that Scala was for intellectuals who care about the future of our species.
You know instead of cool scala they are doing the thing where they basically write full blown java inside a file that ends with .scala
Scala
https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite?q=Scala
Haskell
https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite?q=Haskell
Bfffhahahhahahahahahhaa
Jfc this thread.
Erlang murders all these garbage pseudo functional languages. Erlang is a true functional language, all others are cheap imitations and fakes.
i have came to the conclusion FP is for autist and this thread proves it.
F# and Clojure are the FP langs for non-autists
I like Elixir but IMO there is too much focus on webshit like Phoenix and LiveView, puts it in a high risk of getting "Ruby on Rails"-ed.
Be nice if there were a bit more attention given to it as a more general purpose scripting language to replace Python.
Another way to flatten it, though it repeats "Name?" etc. strings too much
{-# LANGUAGE LambdaCase #-}
import Conduit
import Control.Monad
main = do
putStrLn "Name?"
runConduit $ void $ repeatMC getLine
.| foldMC (curry $ case
("John", "Doe") -> do
putStrLn "Hello, John Doe!"
putStrLn "Name?"
return ""
("John", _) -> do
putStrLn "Wrong (nested)."
putStrLn "Surname?"
return "John"
("", "John") -> do
putStrLn "Surname?"
return "John"
("", _) -> do
putStrLn "Wrong."
putStrLn "Name?"
return ""
)
""
I think a really good argument as to why monadic IO is a terrible idea derives from actually looking up the internal definition of it. As in:
newtype IO a = IO (RealWorld -> (RealWorld, a)
This is actually what GHC uses so IO is nothing more than a wrapper around a function as far as the type system goes. Of course, the big wink is that the function inside of IO can be impure.
On top of that, RealWorld is a unit type. A function of the type `() -> (a, ())` would of course be downright useless without impurities. So far so good, so IO is actually nothing more than a type constructor around functions that warns you that they can be impure.
The issue is that for absolutely no reason it enforces an unwieldy programming style where the return value of one impure function must be used as the input value of the next. This is of course what guarantees sequencing, but it's also highly restrictive in how one can program. The system essentially enforces that one do:
let rw, string = getLine rw;
let rw = putStrLn string rw;
let rw, fp = openFile string rw;
And so forth instead of simpy:
let string = getLine;
putStrLn string;
let fp = openFile string;
Is there any advantage whatsoever to enforcing that practice opposed to simply making impure functions callable directly? Monad abstractions or not, you are constantly passing a “RealWorld” datum around in Haskell which is what leads to the code becoming unwieldly. From every branch, from every loop, this “RealWorld” datum that the first function is called with as the program starts has to be returned at the end as it passes through a giant human centipede being eaten and then pooped out again for the next function. This is simply unnecessarily unwieldly for no tangible benefit and this is why code constantly becomes unnecessarily verbose because this “RealWorld” value has to constantly be passed back to whenever the flow control goes.
well if you have a programmatic mcguffin that forces you to traverse a data dependency graph in a certain order (i.e. the RealWorld token), then that means that the absence of such token implies that you can just order computations however you want.
For example, if you call a function that relies on 3 arguments, and you know that one of those arguments is going to need a lot of heap space, you can decide as a compiler to explore that argument first, regardless of its location in the argument list. Then, after you've explored the argument that takes up a lot of heap space, you could use that allocated heap space for your other arguments without allocating any new memory. You then free that memory once you decide you don't need it anymore.
>well if you have a programmatic mcguffin that forces you to traverse a data dependency graph in a certain order (i.e. the RealWorld token), then that means that the absence of such token implies that you can just order computations however you want.
Which is why I suggested at the start the type system should simply discriminate between pure and impure functions and the optimizer should be aware that one can be done out of order and the other can't. This is I assume what Koka does. This is what optimizer already do in languages without the typological distinction if the compiler can simply proof that a function is pure.
A simple solution of partitioning the language of into pure and impure functions where pure functions can only call other pure functions achieves the same, but cuts both the complexity and the restrictions of passing RealWorld around everywhere.
>For example, if you call a function that relies on 3 arguments, and you know that one of those arguments is going to need a lot of heap space, you can decide as a compiler to explore that argument first, regardless of its location in the argument list. Then, after you've explored the argument that takes up a lot of heap space, you could use that allocated heap space for your other arguments without allocating any new memory. You then free that memory once you decide you don't need it anymore.
To be fair, even many strict nonpure languages do not define evaluation order of arguments for this reason.
In fact, any decent C compiler would in a case like
small_type *y = malloc();
big_type *x = malloc();
small_function(x,y);
free(x);
free(y);
First inline small_function, and then proof probably be able to simply re-use the same address space indeed if it can prove that this is possible without altering program semantics and actually call the allocation for the big type first which is bigger.
Compilers do these things nowadays.
The whole point of hiding RealWorld in IO is to make it a monad to force the user to do sequential operations resulting in one unique state because that's what CPUs do, even when running SIMD instructions.
It's restrictive because the world is restrictive, I can't access memory I did not yet allocate without running into undefined behavior.
Which is why you keep IO in main as much as possible and do all the out of order declarative backflips you want in pure world.
This issue is that simply having a distinction between pure and impure function on a type level would do the same thing without being so unwieldy and ridiculous in to program.
If a simpe a -!> b type constructorr exited for impure functions and a restiction that they could not be called inside of pure functions, though they could obviously still manipulate them, that would honestly be far cleaner, simpler and less unwieldy.
But then one couldn't claim that it was a “purely functional language”, only that the type system discriminates between pure and impure functions.
All the same opportunities and restrictions on how you can apply or compose pure and impure functions would apply under this system, so I don't see what this accomplishes.
Those would, but in that system one doesn't have to constantly pass a RealWorld value around.
Yes, it's abstracted by monads, which are further abstracted by do notation but that Haskell needed an abstraction on top of an abtraction to make it remotely work shows how unwieldy and silly it is.
And even with all that, some of the example code is still verbose and ridiculous exactly because in some way that RealWorld datum needs to be passed around for every loop, every branch, every call. A unit type being passed through the entire program to simply be deleted by the optimizer at the end, all to stop it from ordering things out of sequence in earlier stages of optimization.
I don't see how the monad abstraction would function any differently to an intrinsic impure function type constructor. If you could sketch out how basic use cases would look with your proposal it'd help to demonstrate how it would be less unwieldy, which I'm not currently seeing otherwise.
The difference is not having to pass RealWorld around all the time, however abstracted, creating unnecessarily verbose code for no reason.
My proposal would simply work like:
main () = sequence
let name = readLine ()
putStrLn $ "Hello, " ++ name ++ "!"
These are all simply effectful functions called with (). Of course they can't be called inside of pure functions on a type level but there is no need to rely on runCont madness to escape from a nested loop any more because there is no value RealWorld value that needs to leak.
It essentially functions the same as any other pogramming language.
>pogramming language
It's ``po'', because it is free.
a -!> b is a -> IO b which forces you to call this "impure" function from other "impure" functions because you can't unpack IO b to b (no, don't use unsafe or you make Simon cry) unlike other monads where you give a default b or pattern match over it and it's done. Besides IO you don't actually need to be verbose all over the place.
I don't understand this example, this reads like using the IO monad, with do and binds and whatnot.
Is the problem that the Cont monad is verbose? I don't even know how Cont could be an algebraic effect.
>for no tangible benefit
Proofs. One could provide their own RealWorld type. You can formally describe the effects of IO with pre and post conditions defined on your RealWorld type. With what you're proposing, these proofs become impossible. Plus, you completely lose equational reasoning for impure functions. It's a massive step backwards.
Scalachads, ww@?
Rule34 on haskell?
Should I use Clojure or Erlang if I want to make an open source server that handles different services, like serving pages made in a custom Markup language for a client to render (kinda like PlayOnlineViewer with .pml files), a chat service, a contact service, mail service, file downloading, authentication....
Which of the two language would be best suited for the task?
haskell. if you insist on choosing between clojure and erlang, I'd go with clojure because you get interop with java
I'm Clojure's strongest soldier and I think you'd have a stupidly easy time making both server and client in a beam language, Erlang or Elixir. OTP makes it trivial.
Choosing Clojure will give you access to the java ecosystem for libraries for all those things, but I assume elixir has a decent ecosystem.
Mail is a different concern because it sucks. Unless you're not talking about email.
For authentication and logins I'd use urbit +eauth
Thanks anon, I'm also a Lisp enjoyer. I used to use autolisp (don't laugh) during my internship as a student and despite what I was using it for I really enjoyed the language. But Erlang really interests me too.
>Mail is a different concern because it sucks. Unless you're not talking about email.
I don't know if it's too ambitious but I had in mind to make up my own take on mailing, all contained within the ecosystem I'm building. Users would be able to mail each others pretty much, but it would be a closed garden.
I'm only talking about the server mind you, for the client you'd be able to use anything as long as you respect the server implementation. But what I had in mind was to make a client that act as a front/renderer for the server, able to parse the markup language the server throws at it and render it like PlayOnlineViewer kinda does.
I'll probably be using C++, but that comes later. I miss this kind of things, my aim is to make a system games who want their own live services would want to use, for free.
>For authentication and logins I'd use urbit +eauth
Nice I'm going to look into it.
You can try having your cake and eating it by using LFE or Clojerl
Btw, while I recommended elixir I'd probably use Electric Clojure for anything user facing I'd want to build, or HumbleUI for native DT applications
Fricking Clojure doesn't even work on Windows
Yes it does are you moronic?
I've only run a few Babashka scripts on Windows, but I know that regular Clojure obviously does work on Windows too since some 10% or so of Clojure devs use it as their dev environment
Elixir has an incredibly overpowered ecosystem (ie relative to its size), we just got an alternative to numpy that can compile to cuda and run llms efficiently lmao. We also have pretty good embedded support and imo a superior (albeit young) data science ecosystem on top of that. The creator is basically trying to eat python and he's succeeding.
But there are some areas where the lack of thousands of autists shows: Like the only guid library currently supported. I forget the name of it but it's maintained by literally one older guy and written in erlang. A bit of spaghetti inside it too, but overall it works.
Tldr elixir is great and I am moving heaven and earth to try and get a job in it but research your use case first to make sure you won't have to reimplement parts of the jvm ecosystem or something.
https://github.com/elixir-circuits/circuits_uart looks better than https://hackage.haskell.org/package/serialport. But then I look at https://hexdocs.pm/lens/readme.html and there's a "Lens." in front of most names. Also they have a "&Integer.is_odd/1", which seems to be making distinctions that only come up when using the Haskell FFI.
>OTP makes it trivial
That obviously requires the person to know OTP, if he wants to do his project in erlang/otp but has little programming in it then it's just not going to work. OTP itself is not trivial and has much higher entry bar than many languages.
I haven't programmed with OTP but I read Armstrong's Thesis it it seems to be wholly integrated with BEAM languages such that you don't have to think hard about it
Haskell every time.
The other ones are just dumbed down versions of FP.
meme
https://www.youtube.com/playlist?list=PL04PGV4cTuIVP50-B_1scXUUMn8qEBbSs
If the language is good enough, you could even do GPU programming on it. Nothing imperative languages can do; functional languages can't do better.
Monadic IO is actually even worse than passing a RealWorld uniqueness type around.
It's using a RealWorld Uniqueness type to create continuation passing style to force a defined evaluation order.
Monadic IO is essentially just programming in CPS which has always eliminated the distinction between lazy and strict languages and exposed an explicit evaluation order.
>Monadic IO is essentially just programming in CPS which has always eliminated the distinction between lazy and strict languages and exposed an explicit evaluation order.
That's not just monadic IO that does that. Everything that involves passing around a uniqueness type practically wrangles the programs into CPS. In fact, this is also the reason some haskellers call Cont
newtype Cont = Cont ((a -> r) -> r
the "mother of all monads", as it puts all computations in a continuation passing style, just like the bind operator does to every other monad instance
I don't really agree it has much to do with Uniqueness types. Functions with uniqueness types can still return and don't really take as argument anything that can be called a continuation.
>newtype Cont = Cont ((a -> r) -> r
should be
newtype Cont r a = Cont ((a -> r) -> r)
Composing uniqueness with anything else devolves into monad transformers with State and Cont.
Just keep uniques and IO in main and avoid uniques/IO propagating.
abomination of a language, use
Racket
Scheme
Julia
Clojure
these are all good languages but they can't do what haskell does (have a good type system)
Why are you so obsessed with it?
it's a generally well-designed language that has a good selection of libraries. that's about it
Anyone use functional programming for robotics?
I use serialport to send gcode. Galois uses it for code generation (copilot, ivory) because it's not realtime.
Did someone say catgirls? No? Well too bad.
thread is just a bunch of morons arguing about monads, good job IQfy.
uwu
you vill contain ze IO in ze main with ze monad and have ze pure program instead of spreading unique aids all over functions with asterisks in the type and you vill like it
Does Haskell have namespaces?
No, it has modules. You can't have different packages of functions in the same file, you have to put them in separate files and import them qualified (import foo, bar, baz as module.foo, module.bar, module.baz).
You could use OverloadedRecordDot and put most of your code in the HasField instances. Then each type has it's own namespace. I don't like that HasField's functional dependency prevents 'instance Num x => HasField "x" X x", type errors are worse, HLS doesn't give completions, and when I write the instance I have to write out the type. In spite of those complaints, I'm on the fence about this style:
data Elephant
data Car
instance HasField "trunk" Elephant Int
instance HasField "trunk" Car Char
main=do print dumbo.trunk; print vehicle.trunk
every single fp thread derails into morons arguing about monads.
a simple concept you can teach children but not intermediate java developers, tainted as they are.
There would be no such issue if Monad was just called FlatMappable.
>FlatMappable
Terminal Java brain cancer
Works for Foldable and Traversable.
Is that the only objection that you have for a name that reflects the usage?
>yes of course, I love FlatMappabled error handling
I don't say "Monadic error handling" either.
Well, I do. Whatcha gonna do about it?
That just shows people here have no real knowledge or interest in FP
I already have LINQ. The rest of FP is bloat.
>I already have LINQ
lmao. .NET gays are hopeless.
haskell is a meme
flatmappable doesn't really describe the bind part though does it?
The map part literally does?
?
bind and flatMap are the same function
C, C++, and Haskell are the the only white heterosexual male programming languages. The others are for troons and Hindus.
Haskell is literally full of troons
They all moved to Rust. Unironically.
They still recommend to learn Haskell too.
Maybe as a curiosity but now it's time to Rewrite It In Rust (tm) (c) (r) (sponsored by the Rust Foundation).
Straight white male here, frick trannies, they'll never be women, sneed.
Rust is an excellent language. The tooling is awesome. I don't miss C/C++ clusterfrick of ideologies and styles. Still use it for some stuff because Rust tooling doesn't support some exotic shit I work in, but otherwise link to Rust libs and all UI is in rust. Unironically started learning rust to hate it on it more effectively.
Its no bad at all. Kind of the "next step" in systems languages.
Rust is a good language but you have to deal with a community that superimposes the language’s symbol on the homosexualtroonBlack person flag and makes that their discord’s icon.
I have so far survived without ever joining that discord. No one I know who writes Rust is on that discord. Maybe just forget it exists and try writing rust with existing documentation and github examples. I think all the gender shock troops are contained at this point to their own club.
I don't know am I off base here? Who makes design decisions for the language? Everything seems more or less reasonable to me. If you disagree with something usually reading the history of why the decision was made clarifies the situation and makes sense. Whatever it is, its so much better than C/C++ cacophony of boomer design patterns.
>all UI is in rust
Wait really? What are you using?
slint (like a sane person)
Thanks, any rec for TUIs?
It isn’t from what I can tell. The only troonery I found is a Ukrainian flag on the GHCup homepage.
Are you a zigger or something?
Functional programming just isn't for you, Kolya, go back to php
No.
wtf i love haskell even more now
Slava ukraini is basically blm and pride-tier virtue signaling homosexualry as far as I care
Sounds like something a shitskin would say
It gets real old seeing a bunch of morons that can't find Ukraine on a map spouting slava ukraini every chance they get so they can show off what a good goy they are.
>if you hate my virtue signaling eyesore you're a <bigot | transphobe | shitskin>
you're just as insufferable as they are
it's just as insufferable when they can find ukraine on a map.
c-nile boomer contributes to the thread, thx boomer
oh look a israelite troony, someone tell zher about rust
>is haskell based?
it's ok
>what are some usecases?
those leetcode like websites, contributing to calibre
>where do I start?
I tried haskell first, got along in some exercises and textbooks.
I tried ocaml next, and I ended up liking that one more
I've never tried elixer but I did try the erlang based lisp
Just try the ones you want to use, and see what you like.
read your land of lisp™