Тёмный

1 Problem, 6 Programming Languages (C++ vs Rust vs Haskell vs APL vs Clojure vs Scala) 

code_report
Подписаться 60 тыс.
Просмотров 89 тыс.
50% 1

A video taking a look at 6 programming language solutions (C++, Haskell, APL, Rust, Clojure & Scala) to one problem.
ADSP The Podcast: adspthepodcast.com/
Point Free Programming Talk: • "Point-Free or Die: Ta...
Github Links:
C++: github.com/codereport/LeetCod...
Haskell: github.com/codereport/LeetCod...
APL: github.com/codereport/LeetCod...
Rust: github.com/codereport/LeetCod...
Scala: github.com/codereport/LeetCod...
Clojure: github.com/codereport/LeetCod...
Follow me on Twitter: / code_report
Follow me on Github: github.com/codereport

Наука

Опубликовано:

 

26 дек 2020

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 350   
@taylorallred6208
@taylorallred6208 3 года назад
I love the way you talk about the "beauty" of a solution. It's that sort of thing that reminds me why I love programming. Thank you :)
@carlislenightingale8853
@carlislenightingale8853 Год назад
I prefer the haskell solution to the APL one, because in haskell everyone can get a clue of what is going on whereas with APL you have no clue what you are looking at.
@JasonMitchellofcompsci
@JasonMitchellofcompsci Год назад
@@carlislenightingale8853 It does require knowing what two symbols mean. But the Haskell is in a similar boat because very few people would expect reading it what the compositional operator is actually doing. For people who don't know it's essentially modifying the order of operations.
@svenyboyyt2304
@svenyboyyt2304 Год назад
JavaScript would be a=b=>Math.max(...b.reduce((c,d)=>c+d,0) which I think is a great balance between simplicity and readability
@joshuastein1888
@joshuastein1888 2 года назад
i use C++ for high performance code , Python for interfacing and Haskell to keep my ego in check
@cat-.-
@cat-.- 10 месяцев назад
@@TheRustyCrabwhat is your problem
@everythingtube172
@everythingtube172 6 месяцев назад
this
@DanBader
@DanBader 3 года назад
As a guy who inherited application support for 500,000+ line code base of C and a couple 2-3000 line APL applications i can tell you, I'd much rather see the word MAX written out rather than have to look up every single glyph i stumble upon at 3:30am on a Saturday morning.
@DanBader
@DanBader 3 года назад
Thankfully I've moved on from that job, but the main issues was always taking down one of those special keyboards with 4-5 symbols printed on every key.
@CarlK
@CarlK 3 года назад
I agree. I found APL to be "write only". I couldn't even read and understand my own code after a few days.
@mskiptr
@mskiptr 3 года назад
Could someone enlighten me on some history of APL? It looks so much like an esoteric language, so why is it in actual industry code? Do people just love it that extraordinarily? Does it have some unique killer-feature, or what?
@tcnymex
@tcnymex 3 года назад
@@mskiptr "APL since 1978": dl.acm.org/doi/abs/10.1145/3386319 Also yeah, we love it.
@xXxBladeStormxXx
@xXxBladeStormxXx 3 года назад
People actually wrote applications in APL? That too 3000 line applications? Wtf
@holothuroid9111
@holothuroid9111 3 года назад
In the Scala solution, it is recommended to skip the curly braces. What you are doing here is creating a block. Blocks return their last expression. This block only has one line and is thus unnecessary.
@khalilzakariazemmoura8995
@khalilzakariazemmoura8995 3 года назад
The APL solution seems to be the most straightforward if i figure out where is the max symbol in my keyboard 😁.
@tullochgorum6323
@tullochgorum6323 2 года назад
​@@alhabshi3k I've been playing with both and prefer the old character set. It was developed by a Harvard professor who was frustrated with the inconsistencies and practical difficulties of conventional mathematical notation. He won the Turing prize for this work. The glyphs are mostly mnemonic and are easier to read than J once you get used to them. Which do you prefer: two plus two equals four 2+2=4 In the best APL version there's an IDE with keyboard shortcuts and point and click buttons. You quickly learn the most common glyphs, and you are writing so much less code that it's really a non-issue. If you get hooked, you can buy a dedicated keyboard for £100.
@arraymac227
@arraymac227 2 года назад
@@alhabshi3k ⌈ is Ctrl+s on the Dyalog keyboard. Googling 'APL keyboard layout' gives some nice diagrams
@c4tubo
@c4tubo Год назад
On my Portuguese keyboard, a curly brace ({ or }) requires pressing 3 keys. Think about how often I need to type that in C++, Rust, Kotlin, Swift, etc. This is one of the reasons that I am now taking a hard look at Haskell or any other ML.
@clintonmead
@clintonmead 3 года назад
In the Haskell solution you could just do `foldl1' (+)` and `foldl1' max` to make the reductions explicit
@TheVralapa
@TheVralapa 3 года назад
Would be interesting to see benchmark between them. Especially the c++ versions and rust (I work as a c++ developer as well).
@MrAbrazildo
@MrAbrazildo Год назад
All the shine would be washed out, as 1 realizes how much is paid for them.
@briannormant3622
@briannormant3622 5 месяцев назад
​@@MrAbrazildoI don't know enough about c++ template( it think the std:: accumulate, max, ect is using templates) to say if the compiler will properly optimize them. But 1 think for sure. The good old for loops will obliterate all other solution. I liked the very first one. Very imperative, very procedural. Easy to follow. The Haskell one was nice too, clean and probably as readable for experienced haskell/FP programmers. But the "improved" C++ ones...
@whaisonw2865
@whaisonw2865 3 года назад
If you don't mind spicing the type signature up you can do this in Rust: fn maximum_wealth(v: T) -> Option { v.map(Iterator::sum).max() } The code in this one looks a bit nicer but the data type are just crazy and you have to parse the vectors first as an iterator. Also notice that by returning an Option you can get rid of .unwrap(). This has also the benefit of returning None when your outer Vec is empty and does not throw an exception like other languages would
@bram9762
@bram9762 3 года назад
The composition operator is just a function, so that makes 4 functions in the Haskell solution.
@pup4301
@pup4301 3 года назад
I watch these so I can get confused, then I can get my brain adjusted to how much I don't know. Lovw the content.
@JohnTurner313
@JohnTurner313 3 года назад
I've been around a long time, learned COBOL on a Burroughs mainframe in the 80s and do cloud architecture and security now. I knew about APL, Haskell, Scala and Clojure but had never seen a solved problem before. All you hear about these days is JS and Python and maybe Go. Thanks for the video, you presented and explained the material very well. It clicked with me vs. a lot of the other coding channels. New subscriber.
@user-tk2jy8xr8b
@user-tk2jy8xr8b 3 года назад
How would the task be solved in COBOL?
@shrayesraman5192
@shrayesraman5192 2 года назад
@@user-tk2jy8xr8b It would be the most verbose solution you can ever seen
@ryantjoa
@ryantjoa 3 года назад
Python: return max(map(sum, accounts))
@code_report
@code_report 3 года назад
Nice, that is nicer than mine: github.com/codereport/LeetCode/blob/master/0217_Problem_1.py
@henrywang6931
@henrywang6931 3 года назад
@@code_report I like comprehension more than map, cos it's more explicit and readable.
@AM-qx3bq
@AM-qx3bq 3 года назад
@@henrywang6931 I definitely could be wrong, but I think the expression in code_report's solution is a generator rather than a comprehension list.
@henrywang6931
@henrywang6931 3 года назад
@@AM-qx3bq yeah the sum can take any iterable so generator would work too. A generator can be declared with a comprehension.
@PatriceStoessel
@PatriceStoessel 3 года назад
i'm currently learning QNial, fun language, APL's cousin (github.com/danlm/QNial7) QNial : max byrows sum accounts
@rban123
@rban123 8 месяцев назад
I find the python solution for this pretty nice: def maximumWealth(mtx): return max(sum(x) for x in mtx)
@Kimbsy1990
@Kimbsy1990 2 года назад
Cleaner Clojure solutions are available using transducers. (transduce (map (partial apply +)) max input)
@NicholasVeselskiy
@NicholasVeselskiy Год назад
The APL solution as someone who doesn't know that language or someone who is new to the language is horrendous. Not to say the C++ solutions are ideal but the for-loop one would be very obvious as to what it's doing for anyone even reasonably familiar with programming. (The rust solution also) I think the Haskell solution is probably the cleanest as someone who has never even programmed before might be able to figure out what it does somewhat. But even if you were Dennis Ritchie himself you wouldn't have the slightest clue what the hell the APL solution is doing without already being very familiar with the language. Less lines of code doesn't always mean better code.
@neociber24
@neociber24 3 года назад
For me readbility is the king, Haskell, Rust are what I like the most. For some languages I suppose the programg just crash if the array is empty
@JasonMitchellofcompsci
@JasonMitchellofcompsci Год назад
Question: Is the later versions of the c++ solutions that are parallelized actually faster? The original solution is easily optimized by a compiler. Is the parallelization basically threads? Because I really think some AVX/SIMD and some forloop unrolling will do a better job speeding things up vs the overhead of dealing with threads for such a simple problem. If I've learned anything from pushing performance in C it's don't obfuscate what's actually happening, select which optimization strategy you actually want for the problem starting with very vanilla code, don't get in the way of an optimizing compiler, know your compiler flags because what people think is optimized (-O3) is nothing compared to what you actually get for free by throwing in a few more flags (as long as let those optimizations work by not giving it already optimized code that's been optimized in the wrong direction.) Because of that I've learned to see any time someone says "this code pattern is always faster.. because this feature", I can't help but say yeah right. I'm sure it's really fast. For example, most time when people use a high level utility to speed something up you get at best 4x speed minus overhead.. hopefully. I've seen that letting fully flagged optimizing compilers work their best it can speed things up ten fold on the regular. If you have really modern hardware that's only going to increase as there are more features to leverage. That's why not getting it its way is rule one for fastish code at ease.
@pauloffborba
@pauloffborba 3 года назад
I love your work!
@alejandroenriquez8508
@alejandroenriquez8508 3 года назад
For me readability is king, only when performance is an issue I would go with more technical solutions. When working with a team, this kind of fancy code tricks make everyone's life a nightmare debugging. Although it is nice to see the possibilities.
@xGOKOPx
@xGOKOPx Год назад
What do you think is unreadable here? Maybe functional C++ solutions, because of a gazillion of namespaces, but otherwise everything is pretty clear. Yes, even APL (in this case at least)
@Iifesteal
@Iifesteal Год назад
Would we not need to add *std::execution::par* to run it parallel in the reduce/transform_reduce functions?
@aLotOfDoubt
@aLotOfDoubt 3 года назад
more elegant clj: (->> data (map (partial apply +)) (apply max))
@TheBlenderblob
@TheBlenderblob 3 года назад
in c++ with funlib this is just const auto wealth = stream(accounts) | map( fold( add, 0)) | max();
@japedr
@japedr 3 года назад
In 3:09, how did you achieve this transition in the video? is it manual editing or did you use a special program for that?
@code_report
@code_report 3 года назад
Microsoft Powerpoint 2019 "Morph" transition
@japedr
@japedr 3 года назад
thanks!
@sasayakah6342
@sasayakah6342 3 года назад
The rust's one is very easy to read! awesome videos
@Cirlotube
@Cirlotube 3 года назад
I don't know if it is actually any better, but in Scala you could also write it as accounts map(_ sum) max
@alpaslaneldemir6904
@alpaslaneldemir6904 3 года назад
Amazing content thanks a lot !
@scoreunder
@scoreunder 3 года назад
I'm learning ocaml and here's the solution I would use (with the Batteries library): let maximumWealth = Array.(map sum %> max) Without the Batteries library you don't get sum or max, but they're easy enough to define in terms of folds: let maximumWealth m = let max arr = Array.fold_left max arr.(0) arr in let sum = Array.fold_left ( + ) 0 in m |> Array.map sum |> max
@noomade
@noomade 2 года назад
that order of application is sacrilegious :)
@fennecbesixdouze1794
@fennecbesixdouze1794 2 года назад
@10:40 that's because you hardly EVER just take the max of two elements in mathematics. Usually you want a max over some array or set, so you always need to feed ⌈ into some combinator. In other words, because we don't teach combinators in schools, a single-glyph for the "max" binary operation simply isn't very useful. In much the same way, mathematics notation doesn't actually use the symbol "+" for the equivalent of APL's `+\`, instead they use something like an upper case Sigma with explicit range bounds etc. I would agree that it would be very nice to teach combinators in middle school, and even teach kids with stuff like Haskell or APL.
@the_cheese_cultist
@the_cheese_cultist 2 года назад
using C# linq (assuming input is the given matrix: input.Select(acc => acc.Sum()).Max(); or alternatively input.Max(acc => acc.Sum());
@noomade
@noomade 2 года назад
would you prefer something like foldl1 max . map (foldl1 (+)) to be explicit about the reduction?
@giannismentz3570
@giannismentz3570 Год назад
the APL solution looked like a trick, similar to those you can do in C, and everyone tells you not to do them, but you still like them and do them. I agree with you that there should be single char operators for mix/max as they are used too often. The single char reduce operator was the division operator and this is confusing if you don't know APL, which I don't, but I get it. Nice.
@NikolajLepka
@NikolajLepka 2 года назад
I suppose you technically could make the Rust solution point-free if you use the function form of the .iter method if you're ok with an extra map: accounts.iter().map(Vec::iter).map(Sum::sum).max().unwrap() My Rust is a bit rusty though, so I'm not sure if this'll work
@kipu44
@kipu44 11 месяцев назад
"My Rust is a bit rusty" 🙂 I know it's not intended but it's a nice pun nevertheless.
@wagcampbell
@wagcampbell 3 года назад
Such a great video 👍 Thanks!!!
@JeremyNasmith
@JeremyNasmith 2 года назад
Using the same data, how different would it be to find the wealthiest bank instead of the wealthiest client?
@neilclay5835
@neilclay5835 8 месяцев назад
Very interesting.
@robertpeszek6892
@robertpeszek6892 3 года назад
It is worth noting that maximum has to be a partial function (throw exception or return something like `null` for empty list). Some people (including me) consider using it a bad code. In Haskell, you could use total alternatives, e.g. safe package: maximumMay . map sum
@robertpeszek6892
@robertpeszek6892 3 года назад
.. or use non-empty list type
@Yupppi
@Yupppi 7 месяцев назад
Damn, thanks a lot! I was just recently thinking maybe I could make a vector calculator with what I had learned and combining this problem to what I had I actually managed to make a pretty neat program that prints out a matrix. Next would be deciding if I should try and use these methods for the arithmetics. Noteworthy: #include for the C++20 solution, it's not you need to import despite the name std::ranges:: and std::views::
@dsagman
@dsagman 3 года назад
Excellent! My father worked at IBM at same facility as Ken Iverson, inventor of APL. My father noted how Ken had his own printer, which in the 1970s was bigger than a fridge and cost a fortune. Why? “Because he invents things.” Now, can you please explain monads?
@tricky778
@tricky778 Год назад
They're just monoi... Sorry
@witoldsz80
@witoldsz80 Год назад
Monad is just a thing you can use a flatMap with, that's all :D Think it through. Sometimes its called bind, chain or is hidden inside a language feature like async/await in JS, but it's still the same. Ugh, the "monad" drama is so boring. Oops, the m-word drama, considering the monad word is forbidden in some "circles" 😄
@tricky778
@tricky778 Год назад
@@witoldsz80 frankly a statement in c++ is an element of a monad isn't it? A function call is flatmap, semicolons between statements are the monoid operator.
@nxtktube
@nxtktube 3 года назад
In clojure + is a variable arg function and calls reduce internally for more than 2 arguments. So below is enough (->> data (map (partial apply +)) or equivalent (map #(apply + %)) (reduce max))
@marciszekely1531
@marciszekely1531 Год назад
or (->> data (map (partial apply +)) (apply max))
@marciszekely1531
@marciszekely1531 Год назад
or even (comp (partial apply max) (partial map (partial apply +))) for a point-free solution
@flyingsquirrel3271
@flyingsquirrel3271 3 года назад
Very cool stuff! But I have to disagree with your ranking here. IMO, Rust is CLEARLY the winner, just because it's the only one that forces you to explicitly state what you want to happen if the sequence is empty. In practice, that's a huge achievement. And although it's doing that, the implementation is still very clean and readable (and also easily parallelizable).
@leo848
@leo848 Год назад
Exactly! Just add rayon, use par_iter instead of iter and you basically get safe threading for free!
@0LoneTech
@0LoneTech Год назад
In Haskell, all you'd have to do is change the type to Data.List.NonEmpty, and that corner case wouldn't exist (relocated to input validation where it belongs). It's also the difference between Monoid (e.g. Sum) and Semigroup (e.g. Max). And yes, they're easily parallelizable (start with Control.Parallel.Strategies). Simlarly, the complaint that the reduction wasn't exposed as the same operation could be trivially dealt with using foldl1 or sconcat. Partial functions including head and tail are still controversial, and it's possible to hide them (e.g. use classy prelude). Still, having exceptions beats silently regarding asm as safe imho. Perhaps the most infamous partial function is divide. Does rustc also enforce nonzero divisors?
@BSenta
@BSenta 3 года назад
What about safety, if the input is empty would all of them crash? In rust, because you used unwrap it is clear. You could have returned a result so the caller can decides how to handle the error
@tcnymex
@tcnymex 3 года назад
In APL, if the argument to this particular program was an "empty array" (array whose dimensions were zero by zero, or 3 rows by zero colums, or zero rows by 3 colums) the program wouldn't crash, it would simply return you an array of dimension zero by zero
@ArnabAnimeshDas
@ArnabAnimeshDas 3 года назад
In every language you can handle the error if you want to using conditional flow. This causes undefined behaviour if the error is not handled. In Rust you have to handle the errors mandatorily.
@cryptoworkdonkey
@cryptoworkdonkey 3 года назад
Maybe anyone know where everybody can order APL-glyphs KeyCups?
@RachelBowyer
@RachelBowyer 3 года назад
You can write the Haskell solution in Clojure! (def maximum-wealth (comp (partial apply max) (partial map (partial apply +)))) "apply +" is needed in Clojure to use + in vector form "apply max" is needed to use max in vector form "partial" is needed as Clojure does not curry functions "comp" is the Clojure way to do function composition Having said that I believe your Clojure solution is more idiomatic and the Haskell solution is cleaner than either Clojure solution!
@8bitcoder
@8bitcoder 3 года назад
Could you do a performance comparison with larger arrays, such as 1,000,000 x 1,000,000? How much memory is used? How large are the executables, etc. Thanks! Really interesting video.
@EricMesa
@EricMesa 3 года назад
Wow, haskell and apl are so beautiful. Also, now I understand why some coders loved haskell during advent of code
@cataclysmwarshulduar
@cataclysmwarshulduar 3 года назад
The question is ill-formed because what happens if the array is empty? Rust makes this problem apparent because you called unwrap. It also showed why I think algorithms in C++ is not entirely useful because it requires so much ritual to get anything done that you question why you did it in the first place. Without pipes, the control flow is not entirely obvious. Admittedly, some of these are done for performance reason, namely, entering the begin and end pointer makes sense in low level terms, but not entirely natural in the way piping are done since something like this is usually achieved by performing a filter instead.
@tcnymex
@tcnymex 3 года назад
In APL, if the argument to this particular program was an "empty array" (array whose dimensions were zero by zero, or 3 rows by zero colums, or zero rows by 3 colums) the program wouldn't crash, it would simply return you an array of dimension zero by zero
@cataclysmwarshulduar
@cataclysmwarshulduar 3 года назад
@@tcnymex that sounds....useless and at best sounds like an honest mistake. Max operation simply does not have an identity so its literally impossible to call Max on an empty array. I have spent many nights pondering upon this problem but I am simply too stupid to come up with anything clever beyond returning Option
@steffahn
@steffahn 3 года назад
@@cataclysmwarshulduar One can count negative infinity as an identity for max. But adding a negative infinity to your numbers is pretty much like adding a None value with Option, so yeah..
@LionKing-qp1lk
@LionKing-qp1lk 3 года назад
For-for loop and left-folding are single-pass algorithms. Mapping and then searching maximum needs two passes. 2d array to number folding in clojure: (reduce #(max %1 (apply + %2)) Long/MIN_VALUE accounts)
@bediakogeorge4488
@bediakogeorge4488 3 года назад
Second reduce not necessary. Clojure's max function takes variable number of parameters.
@bediakogeorge4488
@bediakogeorge4488 3 года назад
Can use apply instead
@bediakogeorge4488
@bediakogeorge4488 3 года назад
Oh, and why apply over reduce? stackoverflow.com/questions/3153396/clojure-reduce-vs-apply#:~:text=The%20beauty%20of%20apply%20is,work%20with%20variable%20args%20case.
@LionKing-qp1lk
@LionKing-qp1lk 3 года назад
@@bediakogeorge4488 nice quotes. I don't like java-world constant in my solution. You help me to avoid it at all. 1. I want to illustrate why fold is more preferred than mapping and searching => (reduce ,,,) 2. Reduce => I expect to see custom (fn [acc el] ,,,) and maybe a big transient accumulator 3. When I already have a function in my left hand and a collection in the right hand: cons-this-f-to-list-and-eval ~ apply ------------------------ 4. You ask why I prefer one function over other in case they both work. Because of link, I assume you know classic answer "it's not about speed, it's about the way of thinking". Speed: - dropping intermediate results is anyway more important - usually you don't care if they have a little difference in speed because faster collections = faster computing (I bet matrix libs or java primitive arrays with areduce are faster) - unchecked-math magic can change everything Comfort of a man who write both functions in one top-form: Reduce is like a contract "I'll convert collection to result". Do it. Why you need second reduce if you have only one collection?.
@CraigPerry
@CraigPerry 3 года назад
@@LionKing-qp1lk I didn't understand: You help me to avoid it at all. -- are you saying there's a refinement possible to remove the Long/MIN_VALUE ?
@martinalcala4823
@martinalcala4823 2 года назад
We can get a functional definition with JavaScript too! With: const maxWealth = compose(max, map(sum)); We just need this simple helper functions: const map = fn => list => list.map(fn); const sum = list => list.reduce((acc, val) => acc + val, 0); const max = list => Math.max(...list); const compose = (...fns) => arg => fns.reduceRight((value, fn) => fn(value), arg);
@xavierjulien31
@xavierjulien31 3 года назад
Suggestions on material to use to learn apl? RU-vid didn't seem to have a sound support for it, udemy neither. I found microapl.com but I like multiple resources to learn from.
@tcnymex
@tcnymex 3 года назад
Dyalog.com (APL interpreter company) points to tryapl (an apl console in a browser). Dyalog site also has learning manuels etc. Dyalog also runs a yearly student programners contest with cash prizes & a trip to annual APL conference.
@code_report
@code_report 3 года назад
1. TryAPL.org for a quickstart 2. ru-vid.com for free conference videos 3. chat.stackexchange.com/rooms/52405/the-apl-orchard APL Orchard to ask any questions you have 4. dyalog.com for free software download 5. aplwiki.com
@xavierjulien31
@xavierjulien31 3 года назад
Thank you, looking into it now
@gscacco
@gscacco 3 года назад
In this example the problem fits perfectly the language (APL). In every day programming rarely you will find a mathematical problem like this. What about a web server connected to a MySql db ?
@JaycenGiga
@JaycenGiga 3 года назад
I am by far no expert, but AFAIK, the Dyalog implementation of APL has .NET interoperability. Also, a Database table is more or less a matrix for APL, so you could actually use its strong array capabilities for processing databases.
@Baptistetriple0
@Baptistetriple0 Год назад
My Solution in Rust would be accounts.into_iter().map(IntoIterator::into_iter).map(Iterator::sum).fold(0, i32::max) yes we could use the advantage of .max(), but it return an option and I don't really like unwraps, you could do a unwrap_or(0) but thats one more line, fold is as readable in my opinion and let you directly place a default
@haskell_cat
@haskell_cat 3 года назад
Haskell version in which "maximum" is last because it happens last: map sum >>> maxiumum in which each sum is computed in parallel: maximum . parMap rseq sum in which the two reductions are explicit: ala Max foldMap . fmap (ala Sum foldMap)
@noomade
@noomade 2 года назад
You should make some videos buddy!
@tricky778
@tricky778 Год назад
Doesn't ghc have a flag to parallelize automatically? As a pure functional language it shouldn't need to be requested in code.
@tricky778
@tricky778 Год назад
Maximum doesn't happen last, it happens progressively. Maximum begins and upon requiring the sum of the first list element, a sum of one list begins, and so forth. Depending on the selected numerical type, the sums might progress together too, though I couldn't give you an implementation of that type and it's NUM instance off the top of my head.
@haskell_cat
@haskell_cat Год назад
@@noomade I do, check out my RU-vid channel by clicking on my avatar!
@haskell_cat
@haskell_cat Год назад
@@tricky778 It's theoretically possible, but in practice parallelizing everything makes programs slower, not faster, because it introduces some overhead. That's why annotations are currently needed. In theory a sufficiently smart compiler might be able to only parallelize where it improves performance, but that's much harder!
@dmitrychurkin4077
@dmitrychurkin4077 3 года назад
Awesome, BTW, reminds me Context Free channel. Your brother's name Tom? :)
@harshrathod50
@harshrathod50 3 года назад
Very useful content. I didn't knew reduce and transform like things exist, before this. I better learn them. 😇
@OrbitalCookie
@OrbitalCookie 3 года назад
What did other languages than Rust do when you call max on an empty sequence?
@nicotollenaere1587
@nicotollenaere1587 3 года назад
They throw an exception. Or at least Haskell does. But there is not really another sensible behaviour anyway
@flyingsquirrel3271
@flyingsquirrel3271 3 года назад
That really is the key question here! And that's what puts rust lightyears ahead all others in this comparison. It forces you to consider that edge case.
@dukereg
@dukereg 3 года назад
APL returns 0. I'm kinda disappointed because it gracefully handles many complicated things in ways that make far more sense than that.
@danielsimon424
@danielsimon424 3 года назад
@@nicotollenaere1587 But only because the maximum of list of numbers is "difficult" to define. The map should not be a problem...
@nicotollenaere1587
@nicotollenaere1587 3 года назад
@@danielsimon424 I'm not sure what you mean by that. You could imagine that max would work along with a typeclass Ord' that also defines a minimum element, I guess. In this case max [] (if [] has been inferred as an integer list) would return MIN_INT. I'm not sure most people would find that natural. Really, there are only two sensible choices : either give it a type max :: [a] -> Maybe a (which is the same thing as in Rust) or just throw an exception. It's a matter of taste.
@ftinkere
@ftinkere 3 года назад
Clojure have transducers, they may do it more expressive and shorter
@PS-dp8yg
@PS-dp8yg 3 года назад
Just like you, in my day-to-day work, I avoid for loops, while loops, and do while loops like the plague if possible. I'm a JS developer by day, but I'm learning Haskell on the side. The more I work with Haskell, the more I love it.
@ReedoTV
@ReedoTV 3 года назад
I don't like that APL one at all. Seems fine in isolation, but I reckon it would have the Perl problem of a script being a cluster fuck when you come back to it years later
@julesgosnell9791
@julesgosnell9791 3 года назад
What is the fixation with threading macros in Clojure ? I also find the anonymous function shorthand ugly - I much prefer: (reduce max (map (partial reduce +) accounts))
@jonseltzer321
@jonseltzer321 3 года назад
Alternate: (defn max-wealth [accounts] (reduce max (map (partial apply +) accounts))) Video went out of it's way implying Clojure did not have a 'sum' function (e.g. a function that can add more than two values together). Of course Clojure's '+' function does exactly that already (+ 1 2 3 4 5)
@okcomputr
@okcomputr 3 года назад
Once you get used to them, the threading macros are second nature to use and to read as well, and they make for concise clear code. In the beginning I had to stop and analyze code that was using them for a few minutes before it really made sense, but its something you can get accustomed too pretty quickly.
@julesgosnell9791
@julesgosnell9791 3 года назад
@@okcomputr I agree that they have their uses - but in many cases I find them just adding unnecessary complexity - e.g. the example in this video - why, when we have an established and simple syntax, choose to use a more complex one and turn a two-liner into a three-liner ? - I have often seen this done - particularly in a video that should be showcasing the simplicity, brevity and beauty of Clojure/LISP rather than it's ability to toss in arbitrary transformatory macros ? Why when you have finally wrapped your head around an "inside-out" Polish notation would you then use it to write a macro to allow you to scatter random pieces of "outside-in" code with more complex rules around the use of parentheses than your original ? Why, when you have mastered the concepts of recursion and nesting would you want a macro that hides all of this ? It is like trying to read a novel where every few lines you come across some cryptic symbol notifying you that you should stop reading from left->right and start reading right->left - a jarring paradigm shift - .... and all because the author has seemingly not been able to wrap his head as far around the LISP paradigm as you have and would rather write procedural-looking code...or is patronising you by assuming the reverse... end rant :-)
@CarloSciolla
@CarloSciolla 3 года назад
@@julesgosnell9791 while I agree that "less is more" generally speaking, my eyes (trained by years and years of reading and writing clojure professionally) tend to fair better parsing a threading macro form rather than nested forms in most cases with more than two function calls, mostly because such macros do the job for me of letting the forms boundaries "pop off". And if I eventually use nested forms I tend to use newlines / indentation to improve the EDN parsing speed of human eyes (or maybe just my eyes, no need to generalize). All in all it is, I believe, personal preference and possibly more of a style choice (apropos: github.com/bbatsov/clojure-style-guide#threading-macros), but as a bit of a tongue-in-cheek counter argument: why, when you mastered homoiconic languages and macros, mixing thread-first and thread-last together to fit LISP forms into each other like puzzle pieces, would you ever consider the more mundane nested forms more lispy? :-)
@ryanburnside9541
@ryanburnside9541 Месяц назад
It's become abused culturally. Along with the map-itus. They forget to abstract arrows into selectors and end up churning out reams of arrow macros doing the same thing over and over again. I consider them syntactic saccharine since they actually cause things in the body to be missing one parameter. Do they have a place? Sure in small isolated pockets, when half of your code is the same arrow macro pasted over and over it's hot garbage.
@niklkelbon3662
@niklkelbon3662 Год назад
Why you need to do all in 'raw loops' or all in 'algorithms' ? Why not int maximumWealth(std::vector& accs) { int max = std::numeric_limits::min(); for (auto& row : accs) max = std::max(max, std::reduce(begin(row), end(row))); return max; } ??? It is much more readable then two accumulates or smth
@Chalisque
@Chalisque 2 года назад
Something I was playing with recently was writing sha256sum in C, C++, Rust, Python and other languages. I had no idea where to begin writing it in Haskell, so googled around and took a peek at what someone wrote earlier. For that, the Haskell ends up verbose and ugly compared to C and Rust.
@RaphaelBobillot42
@RaphaelBobillot42 Год назад
I know I'm late on this video, but the Scala solution could have been way shorter, actually you can declare it as a simple lambda expression :) val maximumWealth: Seq[Seq[Int]] => Int = _.map(_.sum).max
@cogspace
@cogspace 2 года назад
// The JavaScript solution isn't far off from Scala: const maximumWealth = accounts => ( Math.max(accounts.map(sum)) ) // Although you do have to BYO sum function: const sum = _ => _.reduce((a, b) => a + b)
@michaelmonkenbusch5591
@michaelmonkenbusch5591 2 года назад
Fortran: maxval(sum(x,dim=1)) full program: integer :: x(3,3) = reshape([3, 7, 2, 8, 10, 2, 3, 3, 4],[3,3]) print*, maxval(sum(x,dim=1)) end
@tcnymex
@tcnymex 3 года назад
(N.B. This comment is about ADSP podcast; didn't see anywhere to leave a comment on an episode on the podcast page) Conor, My ears perked up when you said any scan is parallel-isable The the formal definition of plus scan a series of numbers like iota 4 equal to 1 2 3 4 is a series of reductions +\ iota 4 is: (+/1),(+/ 1 2),(+/1 2 3),(+/ 1 2 3 4) Because plus is both commutative and associative you can parallelize the +/ first, and then run the +\ as four +/ on four separate cores each of which is running the plus reduce parallel algorithm But that only works for things that are both associative and commutative like plus or multiply, it wouldn't work for things like divide and minus scan ( you could, of course, run each of the four ÷/ required for a "÷\ iota 4" on a separate core, but I don't see how you could parallelize the ÷/ itself) But of course, being an APL guy, I let The interpreter do all the smart optimization, so I very much look forward to gaining some insight from your upcoming podcast episode discussing parallelizing scans. T.C.
@tullochgorum6323
@tullochgorum6323 2 года назад
It's interesting that the OO languages have effectively given up on their claims that OO is the solution to issues of reliability and complexity. Almost all the new features in C++/Java/C# are watered down functional ideas. So why not just use a proper functional language like Haskell or F#?
@thecoolnewsguy
@thecoolnewsguy 9 месяцев назад
Performance 😢
@briannormant3622
@briannormant3622 5 месяцев назад
I think because first performance and memory. Functional programming tends to use a lot of recursion and immutable. And 2, because FP and PP each have their strength depending of the problem: for the problem in the video, FP would be the way to go. Its really adapted and readable. The haskell one was the cleanest by far. Pure procedural, basically the first C++, which was kinda a C solution. Was clean and easy to follow to. And imo, easier to modify if the problem changed a bit. But for some problem, like the ones that need you to look at neighbors in an array, PP would usually be cleaner. I'm eager to know if a better way exist in FP, but the +1 is the best by far with my (limited) experience. I don't see the point (and difference) with the Haskell and Apl solution. Its the same, but someone decided to rename max, maximum, map, with weird characters. By unit of code. Both are 4 longs.
@JasonMitchellofcompsci
@JasonMitchellofcompsci Год назад
Cool. Now do an http request, and find all instances of /get_file/ between single quotes and rank the results by an integer found within the string. Then try to convince people that the haskell that results from that is beautiful. Javascript, scala, go, and rust will do the best in that order. Then clojure, c++, haskell. I don't know how to do that in APL. It would be very cool if it stays elegant. Then I will have to agree APL is cool if it can do that. Not having 50 bajillion text types might help.
@Inficate-bd3qu
@Inficate-bd3qu 8 месяцев назад
A program is beautiful because it is beautiful, not because it is short. I'm fine with people playing code golf but not the entire world is a golf course.
@shanewalsh1573
@shanewalsh1573 3 года назад
С++ somehow seems the most readable one
@voiceofthetrue1849
@voiceofthetrue1849 3 года назад
The most beautiful & readable solution in my opinion is the Rust one.
@code_report
@code_report 3 года назад
I really like the Rust as well 👍
@ArnabAnimeshDas
@ArnabAnimeshDas 3 года назад
Rust is the best
@noomade
@noomade 2 года назад
I am curious as to why you find that more readable than the haskell one...
@leo848
@leo848 Год назад
@@noomade I find the haskell one more readable, but the Rust one more efficient and fully safe, as the possibility of an empty list must be handled.
@noomade
@noomade Год назад
@@leo848 It is handled in Haskell as well. I think in production development people that know what they are doing (i.e. not me) don't use the lists from prelude
@svenyboyyt2304
@svenyboyyt2304 Год назад
In JavaScript you could do a=b=>Math.max(...b.reduce((c,d)=>c+d,0)) which I think is a great balance between simplicity and readability. You unwrap b with ... after calling reduce on b which takes two arguments: a function and an initial value. c is our sum/initial value and d is each element of b which is then added to c which becomes our new c next iteration.
@markpascual100
@markpascual100 3 года назад
why the dislikes? i'm so confused it's a great video
@neociber24
@neociber24 3 года назад
Good question, I would like to see what people doesn't like. Or maybe just some programming language fanboys.
@alexanderskusnov5119
@alexanderskusnov5119 3 года назад
I think the problem was very simple. Look at Tsoding ru-vid.complaylists
@c4tubo
@c4tubo Год назад
Best example of the elegance of APL. Those 4 symbols literally express the essential mathematical solution; all the rest is noise.
@heeerrresjonny
@heeerrresjonny 3 года назад
I love videos like this! I think Java would be a worthwhile addition to these...especially if you're going to do 3 different versions of C++ lol. Java streams results in a solution that is _very_ similar to Rust, but possibly more readable (assuming RU-vid doesn't destroy the formatting lol): int max = Stream.of(accounts) .mapToInt(a -> IntStream.of(a).sum()) .max() .getAsInt();
@martinlukas6097
@martinlukas6097 Год назад
In my opinion, in the second line it's more concise and readable to do .mapToInt(i -> i).sum(), instead of invoking the IntStream method. Although you do need to know why the mapToInt(i -> i) is necessary - to convert Stream to IntStream by automatic unboxing.
@heeerrresjonny
@heeerrresjonny Год назад
@@martinlukas6097 I had to go back and think this through again haha. My example is expecting "accounts" to be of type int[][] (i.e. an array of int arrays). So, the IntStream.of(a) call is taking an array of ints, converting it to an IntStream, and then summing them. I'm not sure where calling mapToInt(i -> i) could fit in there and have it still compile. mapToInt() expects you to map each item in the stream to a single integer, so calling sum() on it won't work (sum() is a reduction that only works for IntStream).
@Klayperson
@Klayperson 2 года назад
all i learned in the first 5 minutes is that i don't fucking know C++, i'm gonna go cry now
@Megalcristo2
@Megalcristo2 Год назад
I think the best solution for C++ is the first C++11, but using algorithms to do the sum.
@rikihanks
@rikihanks 2 года назад
no need to call unwrap in rust, if you are going to assume the result wont failt just call .max()? with the ? operator
@leo848
@leo848 Год назад
Umm no this won't work unless the return type is fallible, which is not the case here. If the return type was Option one could use the ? operator but it would be useless as the fallible result gets returned anyway.
@danny-jo1rb
@danny-jo1rb Год назад
my own language named “MaxWealth” has an absolutely beautiful solution: ¥ See its just 1 character isnt that beautiful? Much better than the C++ solution
@maraschwartz6731
@maraschwartz6731 2 года назад
Python solve = lambda m: max([sum(x) for x in m]) matrix here as a list of lists of numbers
@user-tk2jy8xr8b
@user-tk2jy8xr8b 3 года назад
Agda has a single symbol min as well: ⊓
@Aziiz1989
@Aziiz1989 2 года назад
another solution for Clojure (apply max (apply map + accounts))
@pthomet
@pthomet 5 месяцев назад
C++, using FunctionalPlus: auto maximumWealth = fplus::fwd::compose(fplus::fwd::transform(fplus::fwd::sum()), fplus::fwd::maximum()); will work on any container, and any numeric type.
@YashTrivedi21
@YashTrivedi21 3 года назад
It's all fun and games until you have to debug 1000 lines of APL and it's just made out of characters. :) Though very informative and good video. Thanks
@JaycenGiga
@JaycenGiga 3 года назад
Now imagine having to debug the same program, but it is 100,000 lines of C++. And I’m not defending APL in this, I am honestly not sure which would be the greater pain in the ass.
@RichardvsHimself
@RichardvsHimself 3 года назад
Often your application / systems code will be lots of names (which you have created yourself) and be just as readable as any other "traditional" language. Just like any other language, you can write code that is unreadable for yourself or others, or you can write code which is perfectly readable and easily maintainable. The power of APL comes when you have to solve problems for yourself, and suddenly you find the relatively small collection of versatile primitives is quite satisfying to work with. On the topic of readability, this bit of conversation had some interesting points chat.stackexchange.com/transcript/message/55173403#55173403 - as an APL chat room, the topic of "why does every think APL is unreadable" comes up every now and again
@randomseed
@randomseed 3 года назад
Fully functional in Clojure: (comp (partial apply max) (partial map (partial apply +)))
@noomade
@noomade 2 года назад
that is interesting... that is like really ugly Haskell :P
@yaverjavid
@yaverjavid Год назад
solution of same in my language to that i had created: array vec = [ Array[4,5,6], Array[6,7,8], Array[88,88,0], ] loop len[{vec}]: uelem vec:$$I = sum[vec..$$I] arr richesIndex = indicesof[{vec},max[{vec}]] print [richesIndex]
@SherubThakur
@SherubThakur 3 года назад
(For me) Haskell is the most elegant language. APL just has massive readability issues (for me?). The outlined good point about APL (i.e. explicit 2 reduces) might be a bad advise when considering from the perspective of other langs. reduce is just too general and its existence in code is problematic (from readability standpoint) IMO, I always prefer to use something more restrictive. Let me illustrate that with an example here is the solution just using reduces. maximumWealth = foldr1 max . foldr (\x xs -> (foldr (+) 0 x) : xs) [] Everything here is a reduce (foldr is Haskell's version of reduce). i.e. maximum is a reduce (maximum = foldr1 max) (foldr1 is just like foldr but uses the last element of the list as base value) summation is a reduce (sum = foldr (+) 0) mapping is a reduce (map f = foldr (\x xs -> f x : xs) []) put another way, when you encounter reduce first you have to figure out what it is doing then you understand the solution (which is the same problem with for-loop). That is why I don't like to use reduce ever as a general rule. I say the solution, where there is no reduce, is far simpler to read - maximumWealth = maximum . map sum
@noomade
@noomade 2 года назад
foldr (+) 0 == foldr1 (+) ????
@petrushoc
@petrushoc 3 года назад
Kotlin val accounts: List val res = accounts.maxOf { it.sum() }
@sanzharbekamatov1581
@sanzharbekamatov1581 Год назад
Scala solution is most readable and elegant at the same time. It seems like a pseudo code. accounts.map(_.sum).max Even you don't know scala you can read this code and understand what it does.
@rauljosegarcia
@rauljosegarcia Год назад
People are bothered by the smallest things lol. Some will prefer to not have to memorize a new symbol and instead use a very short word like min/max, but definitely to each his own. It IS interesting to have a symbol for those.
@werren894
@werren894 3 года назад
literally programmer these day
@obengkuning3260
@obengkuning3260 3 года назад
Scala is java right?
@markehammons
@markehammons 2 года назад
it's a jvm language that is mostly compatible with java
@DanielKos
@DanielKos 3 года назад
From all C++ versions I'd choose that with two for loops. It's very readable. C++17 is the worst IMO. Too many technicalities exposed.
@hansiraber
@hansiraber 3 года назад
yea, he has no clue what he's talking about. "i love algorithms". he's gonna have a heart attack when he discovers all algorithms are made out of compare and conditional jumps :D
@DanBader
@DanBader 3 года назад
Agree, though i could be swayed to one of the newer versions for the built-in parallelism. Since everyones phone has 4 cores to throw at the problem. Lol.
@insertoyouroemail
@insertoyouroemail 3 года назад
@@hansiraber why is that a problem?
@markbteeps
@markbteeps 3 года назад
That's exactly what I thought. The one with for loops is simple and easily understandable. Having said that, I'm an engineer who programs things, rather than a software developer, so I'm not particularly familiar with modern c++ features. Neither are the people who might try to read or maintain my code though, so for loops seem like the way to go for me. I don't really get the benefit of the newer features.
@mskiptr
@mskiptr 3 года назад
Don't for loops expose the technicalities way more? I mean, the only thing closer to the actual implementation and farther from the underlying idea would be explicit go-tos and conditional jumps… IMO, Haskell version is the most readable because it explicitly states we want the maximum of sums. I.e.: maximum = maximum of = . sum = sum s = map The C++ 'algorithms' versions are kind of halfway through. Like if someone inlined the definitions of maximum and sum by hand. But loops are one step of inlining farther. And bring mutability to the table - which is probably the actual reason he dislikes them.
@vivekkaushik9508
@vivekkaushik9508 Год назад
APL seems like a language Aliens would use to talk to each other.
@cplusplussizeddick1430
@cplusplussizeddick1430 3 года назад
Ok, it's two lines of code, whoopdidoo. But now what's the time and space complexity in comparison to C++ huh? Everything looks cool and all at first sight until you realize it's inefficiently using resources
@philippjungkamp3760
@philippjungkamp3760 3 года назад
In that case I would consider Rust a contender by performance. The solution he presented seems obviously single threaded but I'd like to point out that by including rayon, one could replace .iter() with .par_iter() and the calculation would work in parallel. Safety-wise it's nice that C++ just returns 0 on an empty accounts list. The Rust solution would need an .unwrap_or(0) instead of just unwrap() to not crash on an empty list. With those modifications Rust would contend in speed with C++ but still be easier to read. (I prefer Rusts default choices of immutability and type inference to manually typing auto and const time and time again)
@JaycenGiga
@JaycenGiga 3 года назад
I don’t know if you mean these languages, but both Haskell and APL have so-called fusion, meaning that multiple traversals through a data structure are be combined into a single one by the compiler. That means that the complexity is actually exactly the same as in C++. Rust Iterators are lazy, so the same applies to it. Plus, all three programs are trivially parallelizable (In Rust we use par_iter, in Haskell parMap or something similar and in APL we can supply an evaluation strategy, including GPU calculation, and just use the exact same program). They are actually fast. Rust is known to be faster-than-C in certain situations and APL with GPU computation enabled also has C-like speed for larger amounts of data without much fiddling around. You really don’t have to sacrifice speed for readability, you can have both!
@cplusplussizeddick1430
@cplusplussizeddick1430 3 года назад
@@philippjungkamp3760 interesting. Thanks for the answer
@cplusplussizeddick1430
@cplusplussizeddick1430 3 года назад
@@JaycenGiga oh wow. That's very interesting then. Thanks for the explanation.
@TheDjarEl
@TheDjarEl 3 года назад
Could be interesting to add a 1 million for loop on top of each, a matrix definition (same for each of course) and evaluate the performance :)
@Cstore999
@Cstore999 7 месяцев назад
In my opinion, clojure and rust it's the beautiful solution
@inxiveneoy
@inxiveneoy 3 года назад
Elixir looks pretty good: wealths |> Enum.map(&Enum.sum/1) |> Enum.max
@jdegio
@jdegio 3 года назад
I will submit a Groovy one-liner that strikes a nice balance of readability and elegance: ​def maximumWealth(def accounts) { accounts.collect {it.sum()}.max() }
@currentid
@currentid Год назад
Scala shorter solution: val maximumWealth: Array[Array[Int]] => Int = _.map(_.sum).max
@simonlewis6686
@simonlewis6686 Год назад
Here's my Scala solution: val maximumWealth: Array[Array[Int]] => Int = _.map(_.sum).max
Далее
Functional vs Array Programming
30:40
Просмотров 128 тыс.
2000000❤️⚽️#shorts #thankyou
00:20
Просмотров 6 млн
Super gymnastics 😍🫣
00:15
Просмотров 27 млн
Harder Than It Seems? 5 Minute Timer in C++
20:10
Просмотров 113 тыс.
Async Rust Is A Bad Language | Prime Reacts
28:46
Просмотров 85 тыс.
Functional Programming & Haskell - Computerphile
9:19
Просмотров 657 тыс.
What Can Scala Learn from Rust? by John A. De Goes
59:03
1 Problem, 24 Programming Languages
19:29
Просмотров 372 тыс.
Faster than Rust and C++: the PERFECT hash table
33:52
Просмотров 513 тыс.
C++ vs Rust: which is faster?
21:15
Просмотров 373 тыс.
Dear Functional Bros
16:50
Просмотров 453 тыс.
Сделайте что-нибудь Samsung J6 2018
0:59
Жёсткий тест чехла Spigen Classic C1
0:56
Лучший худший экран - PowKiddy RGB30
12:56