Logs: liberachat/#haskell
| 2025-08-28 09:20:40 | × | arandombit quits (~arandombi@2603:7000:4600:ffbe:2ca2:a28f:2f37:22f6) (Changing host) |
| 2025-08-28 09:20:40 | → | arandombit joins (~arandombi@user/arandombit) |
| 2025-08-28 09:21:28 | × | ljdarj quits (~Thunderbi@user/ljdarj) (Ping timeout: 248 seconds) |
| 2025-08-28 09:21:36 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-28 09:25:29 | × | arandombit quits (~arandombi@user/arandombit) (Ping timeout: 260 seconds) |
| 2025-08-28 09:28:23 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 260 seconds) |
| 2025-08-28 09:35:22 | → | fp joins (~Thunderbi@wireless-86-50-141-108.open.aalto.fi) |
| 2025-08-28 09:37:20 | × | lol_ quits (~lol@2603:3016:1e01:b960:14c0:7a30:3283:d6ed) (Ping timeout: 256 seconds) |
| 2025-08-28 09:38:30 | → | jcarpenter2 joins (~lol@96.78.87.197) |
| 2025-08-28 09:39:39 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-28 09:44:44 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 260 seconds) |
| 2025-08-28 09:51:01 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-28 09:55:35 | → | arandombit joins (~arandombi@2603:7000:4600:ffbe:2ca2:a28f:2f37:22f6) |
| 2025-08-28 09:55:35 | × | arandombit quits (~arandombi@2603:7000:4600:ffbe:2ca2:a28f:2f37:22f6) (Changing host) |
| 2025-08-28 09:55:35 | → | arandombit joins (~arandombi@user/arandombit) |
| 2025-08-28 09:56:01 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 248 seconds) |
| 2025-08-28 09:59:37 | → | confusedalex joins (~alex@user/confusedalex) |
| 2025-08-28 09:59:45 | × | arandombit quits (~arandombi@user/arandombit) (Ping timeout: 248 seconds) |
| 2025-08-28 10:00:31 | × | humasect quits (~humasect@dyn-192-249-132-90.nexicom.net) (Remote host closed the connection) |
| 2025-08-28 10:02:04 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-28 10:02:06 | <kuribas> | I find OOP is just a more restricted version of using HOFs. |
| 2025-08-28 10:02:48 | <kuribas> | I can make a superclass, and call virtual functions inside a method, but it's just the same as having a HOF function taking helper functions. |
| 2025-08-28 10:06:17 | <ski> | a large part of it is programming with product types, with message-dispatching (as dual to sum types, with pattern-matching) |
| 2025-08-28 10:06:26 | → | Lycurgus joins (~juan@user/Lycurgus) |
| 2025-08-28 10:06:54 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 260 seconds) |
| 2025-08-28 10:07:51 | <ski> | (also the product types would typically be non-strict, leading to a closure-type implementation strategy (passing instance state / environment, to operations in vtable)) |
| 2025-08-28 10:10:00 | <kuribas> | The instance being the product type? |
| 2025-08-28 10:10:30 | × | gmg quits (~user@user/gehmehgeh) (Quit: Leaving) |
| 2025-08-28 10:11:39 | <kuribas> | It's true, I don't often see sum types in OOP, usualy they are implicit Unions. |
| 2025-08-28 10:11:52 | <kuribas> | Using isinstance checks to distinguish between them. |
| 2025-08-28 10:12:11 | <kuribas> | In Python I often use "Class1 | Class2" instead of a sum type. |
| 2025-08-28 10:12:24 | × | h2t quits (~h2t@user/h2t) (Server closed connection) |
| 2025-08-28 10:12:25 | <kuribas> | But for parsing it's sometimes useful to have discriminated unios. |
| 2025-08-28 10:12:36 | <kuribas> | Then you get into the mess that is "pydantic". |
| 2025-08-28 10:12:39 | → | h2t joins (~h2t@user/h2t) |
| 2025-08-28 10:13:42 | <probie> | Java these days has pattern matching and you can pretend you have sum types via sealed interfaces, if you want that :p |
| 2025-08-28 10:14:10 | <kuribas> | like scala? |
| 2025-08-28 10:14:23 | <ski> | consider `data Queue a = forall q. MkQ {stateQ :: q,enQ :: a -> q -> q,deQ :: q -> Maybe (q,a)}' |
| 2025-08-28 10:14:41 | <ski> | you can then define wrappers, for invoking the methods |
| 2025-08-28 10:15:37 | × | davean quits (~davean@davean.sciesnet.net) (Server closed connection) |
| 2025-08-28 10:15:55 | → | davean joins (~davean@davean.sciesnet.net) |
| 2025-08-28 10:16:56 | <ski> | enqueue :: a -> Queue a -> Queue a |
| 2025-08-28 10:17:03 | <ski> | enqueue x (MkQ q enQ deQ) = MkQ (enQ x q) enQ deQ |
| 2025-08-28 10:17:05 | <ski> | and |
| 2025-08-28 10:17:12 | <ski> | dequeue :: Queue a -> Maybe (Queue a,a) |
| 2025-08-28 10:17:16 | <ski> | dequeue (MkQ q enQ deQ) = fmap (\(q,x) -> (MkQ q enQ deQ)) (deQ q) |
| 2025-08-28 10:17:24 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-28 10:17:33 | <ski> | and then you can define a class, like |
| 2025-08-28 10:18:28 | <kuribas> | I have sort of the opposite problem, I am writing python, but I don't see a good reason to use a class (other than being more "pythonic"). It just seems less flexible. |
| 2025-08-28 10:18:51 | <ski> | newListQueue :: Queue a |
| 2025-08-28 10:19:04 | <ski> | newListQueue = MkQ [] enQ deQ |
| 2025-08-28 10:19:08 | <ski> | where |
| 2025-08-28 10:19:18 | <ski> | enQ x xs = xs ++ [x] |
| 2025-08-28 10:19:28 | <ski> | deQ [ ] = Nothing |
| 2025-08-28 10:19:41 | <ski> | deQ (x:xs) = Just (xs,x) |
| 2025-08-28 10:19:58 | <ski> | and you can imagine more efficient implementations |
| 2025-08-28 10:21:39 | <ski> | but also note that another way to define this type `Queue a' (where the above type is basically `exists q. (q,a -> q -> q,q -> Maybe (q,a))'), recursively, as `data Queue a = MkQ {enQ :: a -> Queue a,deQ :: Maybe (Queue a,a)}' |
| 2025-08-28 10:22:25 | <ski> | (and then you're redefine the wrappers `enqueue' and `dequeue', for this representation) |
| 2025-08-28 10:22:39 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 260 seconds) |
| 2025-08-28 10:23:20 | × | xff0x quits (~xff0x@fsb6a9491c.tkyc517.ap.nuro.jp) (Ping timeout: 248 seconds) |
| 2025-08-28 10:23:39 | <ski> | "Using isinstance checks to distinguish between them." -- which is kinda a kludge. using VisitorPattern (which is basically CPS, Church representation) is in some sense more principled |
| 2025-08-28 10:24:37 | <Franciman> | what does principled mean? |
| 2025-08-28 10:24:48 | <probie> | less ad-hoc |
| 2025-08-28 10:25:59 | <ski> | if you don't have sealed, or something similar, there's no guarantee there won't be alternatives which are not covered |
| 2025-08-28 10:28:43 | <ski> | btw, if you imagine `codata Queue a where Enqueue :: a -> Queue a -> Queue a; Dequeue :: Queue a', then one could define `newListQueue' as |
| 2025-08-28 10:28:55 | <ski> | newListQueue :: Queue a |
| 2025-08-28 10:29:03 | <jreicher> | The correspondence (if any) between OO and FP is further confused by the OO concept of a class conflating type and implementation. |
| 2025-08-28 10:29:14 | <ski> | newListQueue = listQueue [] |
| 2025-08-28 10:29:21 | <ski> | where |
| 2025-08-28 10:29:21 | <jreicher> | IMO you really gotta be careful with that in OO |
| 2025-08-28 10:29:48 | <ski> | Enqueue x (listQueue xs) = listQueue (xs ++ [x]) |
| 2025-08-28 10:29:59 | <ski> | Dequeue (listQueue [ ]) = Nothing |
| 2025-08-28 10:30:12 | <ski> | Dequeue (listQueue (x:xs)) = Just (listQueue xs,x) |
| 2025-08-28 10:30:19 | <ski> | yes, jreicher |
| 2025-08-28 10:31:33 | <ski> | (`Enqueue' and `Dequeue' here are methods, and `listQueue' is basically the class / class constructor. `listQueue xs' is being defined, in terms of how it responds to "messages", being the methods) |
| 2025-08-28 10:31:58 | <Franciman> | i see OO as more of a ontological programme |
| 2025-08-28 10:32:25 | <Franciman> | than an actual way of implementing stuff. So while i agree that all OO languages bottle the implementation side |
| 2025-08-28 10:32:31 | <Franciman> | i wouldn't say FP is opposed to OO |
| 2025-08-28 10:32:45 | × | takuan quits (~takuan@d8D86B9E9.access.telenet.be) (Remote host closed the connection) |
| 2025-08-28 10:32:54 | <ski> | "OO" can mean many different things (as can "FP") |
| 2025-08-28 10:33:08 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-28 10:33:15 | <Franciman> | the issue with OO is probably how they put mutable state inside things |
| 2025-08-28 10:33:19 | <Franciman> | in a non-controlled wy |
| 2025-08-28 10:33:27 | <ski> | one useful way to contrast and compare, is to focus on the product vs. sum type distinction |
| 2025-08-28 10:33:31 | × | lortabac quits (~lortabac@2a01:e0a:541:b8f0:55ab:e185:7f81:54a4) (Ping timeout: 248 seconds) |
| 2025-08-28 10:33:31 | <jreicher> | My take is that FP is a high-level OO. It creates an manages the objects for you. |
| 2025-08-28 10:33:45 | <ski> | you can do immutable OO |
| 2025-08-28 10:33:57 | <ski> | (O'Haskell, later Timber, did this) |
| 2025-08-28 10:34:10 | <ski> | oh, and OCaml supports it, as well |
| 2025-08-28 10:34:16 | <jreicher> | I believe it's fairly well accepted that a closure is a prototypical immutable object, and a thunk is a prototypical mutable one. |
| 2025-08-28 10:34:49 | × | jreicher quits (~user@user/jreicher) (Quit: In transit) |
| 2025-08-28 10:35:18 | <Lycurgus> | my take is the model of computation, math in the case of FP, a variety of things for OOP, i once said pure phenomenollogy |
| 2025-08-28 10:35:26 | <ski> | to me, "closure" is a particular implementation technique, used for delayed computation values (like first-class function values, "objects", continuations, promises, ..) |
| 2025-08-28 10:35:53 | <Lycurgus> | communicating objects is downtown OOP |
| 2025-08-28 10:35:56 | <ski> | "thunk" doesn't particularly convey any connotation of mutation, to me |
| 2025-08-28 10:36:00 | → | segfaultfizzbuzz joins (~segfaultf@23-93-74-222.fiber.dynamic.sonic.net) |
| 2025-08-28 10:36:22 | <ski> | (it might imply mutation. but might also not imply it. depending on the particular case) |
| 2025-08-28 10:36:37 | → | __monty__ joins (~toonn@user/toonn) |
| 2025-08-28 10:36:44 | <Lycurgus> | there's a legalistic 3 or 4 part qualifying list, encapsulation, inheritance, etc |
| 2025-08-28 10:36:47 | <ski> | in Scheme, "thunk" often refers to any procedure taking no parameters |
All times are in UTC.