1. 6

    Some of the problems in Firefox can probably be alleviated by using one of the user.js projects on GitHub.

    1. 6

      Definitely, but I think one problem that the author is correct in pointing out is that Mozilla has made some very questionable decisions in order to find new sources of funding.

      IMO this is a problem that the open source community can’t and shouldn’t ignore, and I think we should all be very careful about not biting the hand that feeds us and attacking the only non Google entity even attempting to provide a mass market web browser.

      So yeah it’s a tough situation.

    1. 8

      Minor nitpick:

      Furthermore, there is literally no way to tell whether your program will ever actually terminate without actually executing it.

      That is wrong. It is true that it is not possible to write a program that determines for any other program whether it terminates. But for a specific program, in particular for relatively simple algorithms as discussed in the post, it is often possible and not even hard to prove termination.

      1. 3

        Some domain specific languages exploit that: dtrace’s language is structured so that (without some heinous hacks) it’s impossible to not terminate, and given that code written in that language is injected into other code, that’s a pretty useful trait.

      1. 2

        I agree that learning the idioms of a new programming language is important. That’s one thing I liked about Dan Grossman’s MOOC on Coursera. It uses Standard ML, Racket, and Ruby to present different programming paradigms. For example, the segment about Ruby features a very strict interpretation (at least for my taste) of OOP, which was great for contrasting it to the FP approach in ML.

        1. 3

          Wasn’t this domain blocked for spamming ring?

          1. 4

            Submitters were, domain was not.

            1. 1

              I realize that submissions from this domain were kind of spammy in the past. I am not affiliated with the site.

              In contrast to the earlier submissions, I found this article interesting in terms of language design and evolution, and more likely to spark discussion.

            1. 2

              Scala is a great language, but this seems to focus more on usage metrics and history than the Scala language itself.

              I’ll tell you in one sentence a major draw to Scala, more than this whole article: Using the parallel collections library along with functional programming to do concurrent operations on large collections. Parallel programming is made trivial. There are concise examples on the overview page in the standard library documentation.

              https://docs.scala-lang.org/overviews/parallel-collections/overview.html

              1. 1

                IME parallel collections are dangerous. In an interactive application any operation expensive enough that they’d be appealing should probably also be cancellable. They’re actually a good example of one of one of Scala’s ills: a random masters thesis bolted onto the language. They don’t mix well with other Scala defaults, like pervasive use of linked lists, which must be copied into a vector by .par.

                I’m sure they have their uses, but I think that they belong in a library rather than the core language.

                1. 1

                  I’m sure they have their uses, but I think that they belong in a library rather than the core language.

                  Seems like the parallel collections have indeed been factored out into a library.

              1. 1

                Nice post! Where/how do you store the passphrase for automated backups?

                1. 2

                  Thanks! The systemd unit that does the backups talks to pass to get the passphrase. It in turn relies on gpg-agent to not have to ask to unlock the password store. This works for me because I do backups during the day and my email client keeps the gpg-agent awake.

                  1. 1

                    Aren’t you stuck in a chicken and egg problem ? You encrypt your backups using a password, saved in a store. If you loose your whole $HOME, how do you recover ? You need the password, which itself need a gpg key, which is backed up, but encrypted right ?

                    Or maybe you backup your gpg keys and password store using other means ?

                    1. 2

                      Not certain if this is what they meant, but I assume the idea is that they both memorize the passphrase (in case recovery is needed), and also don’t want to keep typing it in for automated daily backups.

                      1. 2

                        Yes, except 1password has it memorized for me.

                  1. 27

                    Can I have yours?

                    1. 2

                      I am not giving you the photo of my face.

                      Is the likeness of my face also secret information? Do you cover your head when you go out in public?

                      1. 3

                        A number is easier to copy than a face in practice.

                        1. 2

                          Do you print your personal ID number at the back of your jacket when you go out in public? It’s not about photo, it’s about a number. If you read the post, you’d see that with the number, we could then

                          Activate a SIM card (and so get an internet connection that’s traceable to you, not them, hiding them from the government)

                          and then do some real damage in your name. That’s the point.

                          1. 4

                            It’s not about photo, it’s about a number.

                            It’s actually about information, which photos do qualify as.

                            If you read the post, you’d see that with the number, we could then Activate a SIM card

                            Just because you can activate a sim card with a non-secret, does not in anyway make the non-secret a secret, or justify that the non-secret should be a secret.

                            and then do some real damage in your name. That’s the point.

                            And my point is non-secrets are not secrets. And that if an authentication system was built on a shaky foundation, that also does not justify or make non-secrets into secrets.

                            1. 2

                              And my point is non-secrets are not secrets. And that if an authentication system was built on a shaky foundation, that also does not justify or make non-secrets into secrets.

                              Okay, with this addition, your point makes sense now. But your original comment, “Passport number is hardly secret information” doesn’t state that explicitly. It seemed to me (and I suspect to the guy asking for your pass #) as if you don’t think sharing it should be a problem because it’s not secret information.

                              Just a bunch of nerds being a bit literal, I guess.

                              1. 1

                                I’m afraid that if a “non-secret” piece of information is considered secret by others then in fact it is secret. If someone can use your passport number to affect your life by entering into phone contracts in your name then you need to stop giving it out. To that extent, what you need to keep secret is decided by others which is admittedly a huge pain in the bum.

                                Very common with government issued numbers of any kind sadly.

                                1. 1

                                  Another thing with this is that you can’t even avoid it in a lot of places. There’s this number, OIB, in Croatia, which is kind of like your government-issued, personal ID number that you shouldn’t give to anyone because it’s used to verify you are you. Except you have to give it to your bank (okay, they need to watch my secrets anyway), my phone company (they sell my info for ads?) or like anywhere you want to get a loyalty card at.

                                  1. 1

                                    We have that here in Sweden too (“personnummer”). It is not seen as a secret at all. It’s simply a numerical representation of identity.

                                    1. 1

                                      Yep, here too. But when you call e.g. your telecom, “hi, I’m X and I need to change my contract.” - “sure, what’s your totally-not-secret #”?

                                      Edit: well, not here, but back there. I’m not in Croatia any more.

                                      1. 1

                                        My real name is not a secret to the government or my bank, but it is to you. No information is either all secret or all non-secret. Secrecy has domains.

                        2. 12

                          I wish we were totally clear as a society about which pieces of info are just identifiers and which represent some kind of authentication or authorization, so we could focus on protecting the right info. And if instead of repurposing IDs as passwords we designed something for authentication from the start, it could be a lot better: we wouldn’t have to handle and store everything in the clear and rotating secrets could be routine instead of a huge deal.

                          (The current mess is also self-perpetuating: the standard approach to authenticating people is pretty weak, but because it’s the standard approach no company using it to book tickets for you, etc. is likely to face much liability!)

                          However, we aren’t in the universe where identifiers and secrets are cleanly separated, so practically speaking I more-or-less understand the qualms about disclosing passport numbers, US Social Security numbers, etc.

                          1. 4

                            whenever I see a wish for X to be designed differently, I love to bring up Chesterton’s Fence:

                            There exists in such a case a certain institution or law; let us say, for the sake of simplicity, a fence or gate erected across a road. The more modern type of reformer goes gaily up to it and says, “I don’t see the use of this; let us clear it away.” To which the more intelligent type of reformer will do well to answer: “If you don’t see the use of it, I certainly won’t let you clear it away. Go away and think. Then, when you can come back and tell me that you do see the use of it, I may allow you to destroy it.”

                            here’s a source regarding why the US Social Security number-as-identifier is the way it is, which really emphasizes how the problem was never about designing good authentication systems, but about developing national authentication in a society that opposes the very idea of national authentication.

                            1. 3

                              That SSA link seems to describe part of what I’m saying (a government record identifier got widely adopted by private DBs), and notes “it lacks…the means to authenticate a person’s identity”, which, yes. It’s not the SSA making a record identifier for themselves that bugs me, or even others using it as a DB key, it’s when folks use it as if it were proof of identity.

                              Spelled-out theory of how we got here: large private entities (airlines, CC issuers, etc., etc.) are capable of better auth than passing around not-all-that-secured numbers in the clear (see chip and PIN, login systems with 2FA or USB keys, etc.). They have been slow to do it (e.g. late introduction of chip and PIN for card-present transactions in the US), and sometimes just have left things a mess (CC card-not-present transactions, and everything using SSN as proof of identity), for a bunch of reasons, including (like I mentioned in the other comment) that they’re not liable for most of the cost/annoyance when the auth system is janky–with credit cards, for instance, the merchants pay the monetary costs and cardholders deal with the fuss of card reissues and false alarms from fraud filters. Competition hasn’t solved it (“use my non-janky payment system/airline/…”) because the network effects protecting incumbents are strong.

                              FWIW, very different to say “it can be informative to look at history” versus assuming historical decisions are wise or ideas are bad unless presented with reams of historical analysis. To me, analogous to “that weird behavior sounds intentional, peek at the history before you change it” vs. a posture that just makes touching your old code nearly impossible.

                              (‘Nother fun thing: the Chesterton quote comes from an essay arguing that proper domesticity was being undermined in the 1920s as indicated by “a multitude of modern manifestations, from the largest to the smallest, ranging from a divorce to a picnic party”. Which is a position that, uh, hasn’t aged well to my eyes and makes you think about the principle used to justify it.)

                              1. 1

                                that’s a really fair point regarding making past mistakes untouchable because of a less-than-useful need for “reams of evidence”. feels like red tape against changing old ideas. thanks for the view

                                I retract what I wrote, I’m not one to advocate for fallacious red tape

                        1. 3

                          I’ve had to write a couple over the years. I enjoyed it immensely. I think the other thing to keep in mind is that even when you’re not designing or implementing an algorithm, good engineering occasionally requires just knowing tradeoffs for correct algorithm selection.

                          So over the years, here’s a few datastructures and algorithms I’ve needed to use while building software.

                          1. KMP search. I also had unique requirements to work on a stream rather than a string so I had to re-implement. Why? I needed to search for something in a HTTP response without buffering and this use case was not well supported by any libs I could find. I ended up borrowing a java implementation from twitter.
                          2. Good old binary search. Why? Needed to find a good compression ratio for an image that didn’t fall below a certain visual similarity score.
                          3. trie: Didn’t implement this one myself, but I needed to rapidly match IP blocks and a simple hash or list wouldn’t have worked. I just used a library called cidranger, but I selected that library because I knew I needed that datastructure.
                          4. Tree traversal. It happens sometimes in surprising contexts (dom manipulation, certain types of reporting, etc)

                          To be clear my position is that software engineering interviews focus too much on CS. Just like Physics and mechanical engineering are separate but related disciplines, CS and Software engineering are not the same thing.

                          1. 1

                            Good old binary search

                            And even that is pretty easy to get wrong.

                            1. 1

                              I also had unique requirements to work on a stream rather than a string so I had to re-implement. Why? I needed to search for something in a HTTP response without buffering and this use case was not well supported by any libs I could find. I ended up borrowing a java implementation from twitter.

                              Note that, unless the stream is somehow interactive (that is, “wait until we have N bytes to read (or there’s EOF)” is unacceptable and we need to find match in what we have right now), this has a simpler solution that is both faster (with a fast memmem() — e.g. from glibc) and lighter on memory than KMP (unless len(pattern) <= 256 and you use 1-byte values to encode the values of prefix function — but then the difference in memory is at most 256 bytes). Here’s the pseudocode:

                              def contains(stream, pattern):
                                  prefix = ''
                                  while True:
                                      chunk = stream.read(len(pattern))
                                      # assume 'memmem()' which is O(N+M) is used for 'in' operation
                                      if pattern in (prefix + chunk):  
                                          return True
                                      if len(chunk) < len(pattern):
                                          # EOF
                                          return False
                                      prefix = chunk
                              
                            1. 6

                              This is practically the exact same procedure as the one described by an Atlassian post on the same subject.

                              1. 5

                                Seems like the original source of both posts is a HN comment.

                                1. 1

                                  I think any article that talks about dotfiles is very similar.

                                1. 4

                                  Relevant: The former president of the ACM tweeted a few days ago that the ACM has adopted “the goal of opening the Digital Library within five years.” I can’t find any further information on that, though.

                                  1. 8

                                    Nice article. It highlights the key point that I made in the MPhil compiler course I used to teach: JITing is easy, knowing when and what to JIT is hard.

                                    A few nits:

                                    Compiling out the machine code for all these cases is not very productive for a variety of reasons, which is what we’d have to do if we wanted Julia to be a compiled language

                                    Not entirely true. In the absence of dynamic linking and function-pointer type casts, you can do reachability analysis and compile only the cases that are reached. Pony does this, for example.

                                    If I “JIT compiled” C similarly to how Julia does it (statically compile each function as it’s called), it would be impossible to make it faster than compiled-C as the compile-time is non-negative and the generated machine code is essentially the same.

                                    This is not really true. For example, a lot of dynamic behaviour in C comes from the dynamic linker. You can’t inline in AoT compiled C across a shared-library boundary but you could with JIT’d C. C programs often have a few functions that are always called with a handful of argument values. Optimising for the ones you see can also improve things (though you could do the same with profile-guided optimisation if you tracked values - most things just track branches). Additionally, if you’re JITing, you can target exactly the hardware that you’re running on: Do you have SSE4 as your baseline or AVX512, what is the relative cost of different vector operations? One of the presentations on the LLVM-based fourth-tier JIT for JavaScriptCore showed that a couple of benchmarks were faster when compiled from C to JavaScript and then JIT’d with JSC’s FTL than they were when compiled with clang, for precisely this reason (apples to apples comparison: both approaches used clang as the parser and LLVM as the back end).

                                    If Pypy decides it needs to compile many things all at once after JITs compiling som functions, then you might have a slow-down in the middle. It also makes benchmark results more ambiguous, as you have to check if the jitted languages were given time to warmup, but you’d also want to know if it took an unseemly amount of time to warmup

                                    Laurie Tratt has a nice paper about this. It’s actually worse than the author describes: JITs don’t always (or often) reach a steady state after warmup

                                    1. 4

                                      Wow thanks for all the information (I’m author) in the first part that’s actually new to me! I actually have been bit by VMs giving me a squiggly line in warmup at peak performance and it was awful c: (I linked the Laurie-article you’re referencing in the post)

                                      1. 1

                                        One of the presentations on the LLVM-based fourth-tier JIT for JavaScriptCore showed that a couple of benchmarks were faster when compiled from C to JavaScript and then JIT’d with JSC’s FTL than they were when compiled with clang, for precisely this reason (apples to apples comparison: both approaches used clang as the parser and LLVM as the back end).

                                        That sounds super interesting. Do you happen to have a link to the benchmark results?

                                      1. 2

                                        For anyone who has struggled with AD as much as me, one of the best way to test your code is to create a local AD server using samba. You can install samba, winbind, and related libs like libpam-winbind and libnss-winbind. Then enable sambad ad-dc, for example on systemd: systemctl unmask samba-ad-dc, and edit the configs in /etc/samba/smb.conf to disable the requirement of strong authentication (for testing purposes) and make sure the realm is correct. After that you will be able to create groups and users via the samba-tool, for example samba-tool user create 'testuser' 'testpassword'.

                                        Finally you can have fun with the script you are working on to interact with AD or test with ldap_search, example:

                                        ldapsearch -H 'ldap://127.0.0.1:389' -s one -D "testuser@TEST.LAN" -w 'testpassword' -b 'CN=Users,DC=test,DC=lan' '(sAMAccountName=testuser)' 'objectClass' 'cn' 'name'

                                        1. 1

                                          I want to add a tool that I found very useful when trying to get various tools to connect to LDAP: Shelldap gives you a nice CLI shell to navigate and manipulate an LDAP tree.

                                          1. 2

                                            I want to add Apache Directory Studio which is a godsend when you want to explore a directory tree

                                            1. 2

                                              ldapvi is also great. We used it to manage thousands of people.

                                          1. 4

                                            I see the appeal of this, but I am not sure how I feel about moving even more stuff into the browser. I tried webmail and moved back to Thunderbird. I tried Overleaf/ShareLaTeX and moved back to TeXStudio. I guess I just like locally installed software.

                                            1. 1

                                              Seems like Java records are pretty much the same thing as case classes in Scala, including the generated code.

                                              I’m looking forward to inline classes. They should make records/case classes even more useful.

                                              1. 2

                                                I’m using the names of boy band members for my private machines. They are short and easy to spell. So far, I have exhausted the Backstreet Boys.

                                                1. 13

                                                  Clojure and Erlang were both designed for the ground up around making concurrency the default, although in the former it was just the language design and compiler, not the whole runtime. The main thing Erlang and Clojure have in common is an insistence on immutable data structures.

                                                  Detecting whether a function is safe to parallelize requires way more detailed information than most compilers have; that would take a type system along the lines of Haskell or more expressive. If you want to learn about automated attempts to introduce concurrency I expect the Haskell people are the only ones even capable of beginning to answer that question. (Outside research-only languages)

                                                  1. 4

                                                    Erlang’s concurrency was designed around multiple communicating machines. It happened that when we got multiple cores on single machines, this model still worked very well.

                                                    OTP (Erlang is usually run on OTP) does have shared mutable state available - for optimisation. Erlang Term Storage or ‘ets’ being an example. I believe Clojure has something called Agent but I don’t know if it’s a similar concept.

                                                    1. 3

                                                      Clojure agents are a way to async queue operations on shared data. It’s basically like an atom, but instead of happening immediately the operation happens at some point in the future.

                                                      It also has software transactional memory but I don’t think anyone really uses that.

                                                    2. 2

                                                      Although I do not consider myself one of the Haskell people, I stumbled across a talk on Improving implicit parallelism in Haskell a while ago.

                                                    1. 16

                                                      It’s clear to me that the author really likes FreeBSD but this comes across as preaching to the choir. There isn’t anything in the article that makes me want to switch to it.

                                                      • How is it rock solid if you have to RTFM and fiddle a bunch of setting to get an FTP server to not need a reboot every 3 days?
                                                      • Why are ports and pkg better than apt?
                                                      • How are jails different than docker or chroots?

                                                      There were parts of the article that I found interesting like installing 3rd party packages to /use/local and the service handling through rc.conf but overall, I get the impression that running this OS requires reading a lot of documentation which is even more of a burden.

                                                      1. 6

                                                        For me the vast documentation is actually a plus. With Linux, I often find answers for my questions at stackoverflow, whereas questions about FreeBSD can often be answered by reading the handbook. I’m not saying one is better than the other, but for me learning about FreeBSD by reading the handbook was an interesting experience. I’m only using it on my home server, though.

                                                        1. 6

                                                          How often do you find yourself googling “ Linux”? That’s a problem you get far less on OpenBSD and FreeBSD because of the quality of the documentation on these projects.

                                                          1. 7

                                                            Maybe, but >90% of the documentation I read has nothing to do with the OS itself, but more what I use/deploy on top of an OS. So, unless you are working in a domain (e.g. routers) where the OS suffices, you are mostly reading third-party documentation anyway. And for third-party software it is often much easier to find support for Linux.

                                                            That said, every Linux user should envy BSD man pages, especially OpenBSD man pages.

                                                        1. 6

                                                          Remember kids, enums spread diseases: https://codecraft.co/2012/10/29/how-enums-spread-disease-and-how-to-cure-it/.

                                                          As for booleans, I generally hold the view that if your module has more than one boolean, you’ve implemented an implicit FSM with a bunch of invalid states. Make it explicit!

                                                          1. 4

                                                            Maybe it wasn’t widely supported at the time, but I’d use enum class members instead of the C preprocessor for this. Something like this in C++:

                                                            class VehicleType {
                                                            public:
                                                              int maximum_speed();
                                                              bool slides_easily();
                                                              FuelConsumption fuel_consumption();
                                                              enum { Car, MotorCycle, Truck, Semi }
                                                            }
                                                            

                                                            Not only because I really don’t like using macros, but also because it makes sense to be able to easily switch to make it a non-enum class.

                                                            1. 3

                                                              Enum classes are a great solution to the problem, when they are available in your language.

                                                              1. 3

                                                                If we’re talking about the same thing, in Kotlin these are “sealed classes” and in Rust they’re just “enums”. In both of these cases, the different variants of the enum can have different structures, because they’re classes instead of just instances. (But they can also be singleton classes.)

                                                                (Compare to Java, where all the variants of the enum have the same structure, because they’re just instances of the same class.)

                                                                1. 2

                                                                  I wasn’t even talking about having data-carrying variants. I was just talking about the ability to associate methods with your enum, mostly lookup tables. In Rust, you can do this with an associated impl block:

                                                                  #[derive(Clone, Copy, Debug, Eq, PartialEq)]
                                                                  enum VehicleType { Car, MotorCycle, Truck, Semi }
                                                                  impl VehicleType {
                                                                    fn maximum_speed(self) -> i32 {
                                                                      match self {
                                                                        VehicleType::Car => 8,
                                                                        VehicleType::MotorCycle => 4,
                                                                        VehicleType::Truck => 8,
                                                                        VehicleType::Semi => 4,
                                                                      }
                                                                    }
                                                                    fn slides_easily(self) -> bool { ... }
                                                                    fn fuel_consuption(self) -> FuelConsumption { ... }
                                                                  }
                                                                  

                                                                  The C++ is actually really close to this, even though it’s technically an enum embedded in a class. What C++ doesn’t have is enums as tagged unions. C++ has a form of tagged unions in variant, but it’s not quite the same.

                                                                  1. 2

                                                                    When using the terms for algebraic data types that’s basically a sum of products.

                                                              2. 4

                                                                That article is about a very different use of enum than this article talks about. Enums used as flags are pretty harmless.

                                                              1. 2

                                                                Very nice write-up.

                                                                I sometimes use calculating the digit sum as an early problem. There you don’t need to handle edge cases and it has no direct mathematical solution. But it is a nice example for comparing iterative and recursive solutions, or to develop a simple algorithm in a Nassi-Shneiderman diagram.

                                                                1. 6

                                                                  Incorrect technically and practically.

                                                                  The first thing to notice is that functors in category theory are not functors in Haskell.

                                                                  In category theory a functor from one category means that you can move objects and arrows from one category into another, such that they keep behaving in the same way as they did in the original category. Note that there’s no notion of type or function there as category theory treats these ideas on more abstract level than a programming language does.

                                                                  In Haskell functor means for a construct that can upgrade a type into something, and then upgrade a function acting on that type to something. There’s no requirement that it keeps behaving the same afterwards. Also sometimes it’s not required that you can lift any object.

                                                                  Examples of ‘haskell’ functors you may have:

                                                                  The functor on the first item of a pair, where some ‘b’ is on the right side. There’s a similar “functor” for the second item of a pair.

                                                                  (a → c) → (a,b) →(c,b)
                                                                  

                                                                  The functor on the codomain of a function:

                                                                  (a → c) → (c → b) → (a → b)
                                                                  

                                                                  The functor on the list:

                                                                  (a → b) → List a → List b
                                                                  

                                                                  Functors in Haskell means for structures where you can “apply” types into a function. Eg. List (toString . (+1)) would produce List Number → List String and the thing you probably get is it adds 1 to each number inside list and stringifies each, giving you list of strings. Actually in Haskell you’d do fmap (show . (+1)) and you can inhabit the type [Integer] -> [String] with it.

                                                                  An example of a category theory functor: A functor from category C to a pair category (C,C). If you take object from C, there’s object in (C,C), eg. for a there is (a,a). Likewise you give it an arrow a → b, you get arrow (a,a) → (b,b). And these things behave in same way they behaved in the original category, except that after the functor they’re in a category that’s larger by a square.

                                                                  In category theory the functor is a stepping-stone to describe natural transformation. Also you get a concept of adjoint functors. The aforementioned functor to pair category gives you products and sums for any category, as adjoints that you can take from the functor.

                                                                  1. 2

                                                                    Most languages’ endofunctors are reasonable functors. Only Haskell is strange, and only because its semantics are extremely quirky. For this reason, many people will tend to work in a “platonic Hask” rather than in Haskell’s actual category of types. The upshot of this is that many Haskellers believe their code to be proven correct when it has only merely type-checked.

                                                                    In other MLs, functors go between modules; we may thus imagine each module as a sort of category, and functors as sending modules to other modules. Modules don’t exactly have the inner structure of a category, though. This is just as well, as the typical ML (in fact, all of the ones I know of!) have weak type systems not capable of expressing functors between genuine categories in toto, just categories which are small enough to fit into the type system containing it. (It may sound like I am being petty here, but I do have to go to untyped languages just to express ∞-categories.)

                                                                    While I like the invocation of the Hollywood Principle, functors are really about composition, not just embedding. It’s very cool that we can write a minimal object and embed it within a richer API, but cooler that we can compose our minimal object out of other, even smaller subobjects.

                                                                    1. 1

                                                                      The first thing to notice is that functors in category theory are not functors in Haskell

                                                                      In category theory a functor from one category means that you can move objects and arrows from one category into another, such that they keep behaving in the same way as they did in the original category. Note that there’s no notion of type or function there as category theory treats these ideas on more abstract level than a programming language does.

                                                                      In Haskell functor means for a construct that can upgrade a type into something, and then upgrade a function acting on that type to something. There’s no requirement that it keeps behaving the same afterwards. Also sometimes it’s not required that you can lift any object.

                                                                      I’m aware that there is a difference between Haskell’s functors and category theory’s functors. IIRC, the connection is that Haskell’s functors are really endofunctors in the category Hask of Haskell types, and arrows are then functions. The functor laws should make sure arrows are mapped correctly (i.e., behave in the same way regarding composition). Please correct me if I’m wrong, I’m still learning.

                                                                      Incorrect technically and practically.

                                                                      Could you expand on this? I admit that the title of my post is not technically correct, but I don’t see where its contents disagree with what you wrote.

                                                                      1. 2

                                                                        Haskell people tend to pay attention to functor laws, but this is not necessarily what happens in the code because the Haskell environment doesn’t require the functor laws. Likewise the constructs can be useful even if the laws didn’t always satisfy. Also I remember at least one dude who has stated that hask is not a category.

                                                                        Functors are not comparable to frameworks. You don’t give up or invert any sort of control there. If things happening here would be sufficient for that interpretation, you could think of any higher order function as a framework because you pass a function in. Although it matches in that you pass a thing to call. But I think being a framework would require you to at least write the phone number down, let function complete, and then arbitrarily call it when you’re already forgotten about the whole thing.

                                                                        1. 1

                                                                          you could think of any higher order function as a framework because you pass a function in.

                                                                          I see. That makes total sense.

                                                                          But I think being a framework would require you to at least write the phone number down, let function complete, and then arbitrarily call it when you’re already forgotten about the whole thing.

                                                                          Isn’t that what happens in asynchronous effect monads?