Logs: liberachat/#haskell
| 2025-12-16 10:48:16 | <dminuoso> | Is `Enum` the typeclass of things that are countable? |
| 2025-12-16 10:48:21 | <dminuoso> | Is Rational Enum? |
| 2025-12-16 10:48:38 | <tomsmeding> | Enum is nothing, essentially, as it has no sensible laws and the methods are nonsense too (can you only enumerate things that are Int-large?) |
| 2025-12-16 10:49:23 | <tomsmeding> | no, because Rational is at least as large as Integer, and Integer is bigger than Int, and you must define fromEnum |
| 2025-12-16 10:49:38 | <tomsmeding> | but that just shows that the Enum class is nonsense, not any kind of enumerability of Rational |
| 2025-12-16 10:49:47 | <tomsmeding> | because Rational is very countable indeed |
| 2025-12-16 10:49:53 | → | somemathguy joins (~somemathg@user/somemathguy) |
| 2025-12-16 10:50:22 | <tomsmeding> | (Enum is useful as a base for [..] syntax, but that's not under discussion here) |
| 2025-12-16 10:52:09 | <dminuoso> | tomsmeding: I think Enum is in a weird state in that it feels like its *meant* to represent things that are countable, since the ability to enumerate seems to align with the mathematical notion of countability. But the [..] and relatedly fromEnum/toEnum make it a somewhat adhoc thing. |
| 2025-12-16 10:52:25 | <tomsmeding> | right |
| 2025-12-16 10:53:19 | <tomsmeding> | it's actually useful for [..] (apart from not being able to enumerate stuff that's bigger than Int, which is nonsense), and it's _almost_ useful for describing enumerability in general, but then falls short |
| 2025-12-16 10:53:36 | <tomsmeding> | it's like Arrow with `arr`, except that Enum actually has some use still |
| 2025-12-16 10:53:43 | <dminuoso> | So we would need a kind of `class Countable a => fromNat :: Natural -> a` |
| 2025-12-16 10:54:07 | <tomsmeding> | I'd like a mapping in the other direction too with a law saying that they are inverses |
| 2025-12-16 10:54:22 | <haskellbridge> | <loonycyborg> I don't see how it represents countability in mathematical sense |
| 2025-12-16 10:54:22 | <haskellbridge> | <loonycyborg> it's merely prerequisite |
| 2025-12-16 10:54:31 | <haskellbridge> | <loonycyborg> but there are many ways of counting the same thing |
| 2025-12-16 10:54:47 | <dminuoso> | loonycyborg: The fromEnum/toEnum are really the same essence. |
| 2025-12-16 10:55:01 | Googulator71 | is now known as Googulator |
| 2025-12-16 10:55:01 | <dminuoso> | Except it's constrained to Int instead of Natural |
| 2025-12-16 10:55:03 | <haskellbridge> | <loonycyborg> that is making a mapping of Thing -> Natural |
| 2025-12-16 10:55:46 | <tomsmeding> | (another problem is that fromEnum and toEnum are not declared in the documentation to be inverses of each other, although we can reasonably say that they "obviously" must be) |
| 2025-12-16 10:56:01 | <dminuoso> | Being countable really means a one-to-one mapping to ℕ |
| 2025-12-16 10:56:27 | <dminuoso> | loonycyborg: It does not matter *how* you count it. |
| 2025-12-16 10:56:38 | <dminuoso> | As long as you *can* provide any way to map to ℕ |
| 2025-12-16 10:56:47 | <haskellbridge> | <loonycyborg> Enum represents only one way that is deemed useful for whatever reason |
| 2025-12-16 10:58:03 | <lucabtz> | dminuoso: countable = finite or 1-1 mapping to N |
| 2025-12-16 10:58:14 | <tomsmeding> | countable = injective mapping to N |
| 2025-12-16 10:58:19 | × | arandombit quits (~arandombi@user/arandombit) (Ping timeout: 260 seconds) |
| 2025-12-16 10:58:21 | <lucabtz> | if finite there is not 1-1 mapping with N, but still countable |
| 2025-12-16 10:58:21 | <dminuoso> | Given that `toEnum, fromEnum` are the minimal methods, and `toEnum` is in principle derivable from `fromEnum`... the loose description in the Haskell report really implies that its something along the lines of Countability. |
| 2025-12-16 10:58:43 | → | arandombit joins (~arandombi@user/arandombit) |
| 2025-12-16 10:58:52 | <dminuoso> | lucabtz: Yes, Enum lacks the ability to talk about infinite sets. |
| 2025-12-16 10:59:00 | <merijn> | and sparse sets |
| 2025-12-16 10:59:14 | <tomsmeding> | merijn: we're talking about countability here, not usefulness |
| 2025-12-16 10:59:32 | <dminuoso> | But that really goes into the line of "Haskell has Int in a lot of places where, morally, it should use Integer or Natural" instead. |
| 2025-12-16 10:59:34 | <lucabtz> | tomsmeding: yeah i suppose dropping surjectivity is the same |
| 2025-12-16 10:59:42 | <dminuoso> | The choice of `Int` in most places is because of history and performance. |
| 2025-12-16 11:00:09 | <dminuoso> | So if we squint a bit, Enum is meant to be that Countable typeclass... |
| 2025-12-16 11:01:11 | <probie> | and also reasonability, `(!!) :: [a] -> Integer -> a` doesn't gain you anything, because you don't have time to walk that very large list (nor enough memory unless it has a cycle) |
| 2025-12-16 11:01:37 | <tomsmeding> | walking Int is also not particularly practical |
| 2025-12-16 11:01:52 | <tomsmeding> | (on modern 64-bit machines) |
| 2025-12-16 11:02:27 | <dminuoso> | probie: That's the other side of it. The [] structure is so pervasive because it both represents control flow *and* data. When its used for data, its a really poor fit because it results in terrible access patterns. |
| 2025-12-16 11:02:52 | × | trickard_ quits (~trickard@cpe-81-98-47-163.wireline.com.au) (Read error: Connection reset by peer) |
| 2025-12-16 11:02:56 | <dminuoso> | So on one hand we favour Int because its much faster due to direct mapping into machine registers, but then we drag those singly linked lists around everywhere. |
| 2025-12-16 11:03:00 | <dminuoso> | A weird state we are in. |
| 2025-12-16 11:03:06 | → | trickard_ joins (~trickard@cpe-81-98-47-163.wireline.com.au) |
| 2025-12-16 11:03:29 | <probie> | but for Enum, it's quite possible to want `[a..b]` where `fromEnum a - fromEnum b` is small, but `fromEnum a` is bigger than int |
| 2025-12-16 11:03:53 | <dminuoso> | probie: Given that `fromEnum/toEnum` are minimal, one could assume that they should not be partial. |
| 2025-12-16 11:04:05 | <dminuoso> | But there's so many bottoms flying around in base... |
| 2025-12-16 11:04:42 | <probie> | Sorry, I was unclear. I mean for things that "should" be `Enum`, if there weren't too many of them |
| 2025-12-16 11:04:48 | <dminuoso> | At least for `fromEnum` an argument could be made that it should behave in a cyclic fashion. |
| 2025-12-16 11:04:59 | <dminuoso> | Or no, I meant `toEnum` |
| 2025-12-16 11:05:37 | <haskellbridge> | <magic_rb> Singly linked lists make sense in many cases due to laziness, but generally one should use vector yes |
| 2025-12-16 11:06:37 | <probie> | as in `Integer` is genuinely a better chouce needed for {to,from}Enum in a way that isn't the case in other places `Int` is used instead (like `(!!)`) |
| 2025-12-16 11:06:38 | <merijn> | magic_rb: I don't think "generally you should use vector" is right. |
| 2025-12-16 11:06:51 | → | deptype joins (~deptype@2406:b400:3a:9d2f:476c:a58e:3471:ff37) |
| 2025-12-16 11:06:53 | <merijn> | Don't get me wrong, Vector is *often* right, but I'm not sure I'd ever recommend defaulting to it |
| 2025-12-16 11:07:01 | <probie> | Vector requires me to copy the whole thing to "change" a single element. This is often not desirable |
| 2025-12-16 11:07:23 | <dminuoso> | I sometimes wish there was a kind of Vector/[] polymorphism, that I could myself decide what I want. |
| 2025-12-16 11:07:29 | <dminuoso> | But something without typeclasses |
| 2025-12-16 11:07:34 | <merijn> | probie: Vector doesn't always copy the whole thing, and also mutable Vector exists :) |
| 2025-12-16 11:07:48 | <dminuoso> | What was that cabal feature along the lines of OCaml functors called again? |
| 2025-12-16 11:07:51 | <haskellbridge> | <loonycyborg> in ST monad? |
| 2025-12-16 11:07:51 | <haskellbridge> | <magic_rb> ^ |
| 2025-12-16 11:07:54 | <merijn> | dminuoso: backpack |
| 2025-12-16 11:07:55 | <probie> | dminuoso: backpack |
| 2025-12-16 11:07:57 | <haskellbridge> | <magic_rb> Yeah vector in ST |
| 2025-12-16 11:08:03 | <dminuoso> | Right backpack. |
| 2025-12-16 11:08:17 | <merijn> | loonycyborg: Vector has a bunch, there's ST, but also IO |
| 2025-12-16 11:08:26 | <merijn> | Depending on your usecase |
| 2025-12-16 11:08:30 | <dminuoso> | Yeah if via backpack I could just swap between vector or list for a given package that would be ideal. |
| 2025-12-16 11:08:50 | <dminuoso> | Of course it's completely unreasonable for 2 major reasons. |
| 2025-12-16 11:09:06 | <merijn> | tbh, I'm a big fan of "just thinking about your data type choices" :p |
| 2025-12-16 11:09:07 | <haskellbridge> | <loonycyborg> But still it's procedural state, in haskell you'd want a persistent structure in general. Unless you wanna go all out for a hotspot. |
| 2025-12-16 11:09:30 | <merijn> | Vector is very good for lots of things, and List good for lots of other things |
| 2025-12-16 11:09:46 | <dminuoso> | merijn: For a library thats tought unless you like to duplicate interfaces. And with duplicated things you get the typical `toLazy/fromLazy` nonsense when passing text between library portions. |
| 2025-12-16 11:10:13 | <haskellbridge> | <magic_rb> Generally List is fine if you dont care about performance and arent storing it around or traversing it in any other direction than linearly forward |
| 2025-12-16 11:10:15 | <probie> | Vector is very good for lots of things, and GHC does some very heavy lifting to make List good for lots of other things :p |
| 2025-12-16 11:10:42 | <merijn> | dminuoso: A library should use whatever's best for said library |
| 2025-12-16 11:10:51 | <merijn> | especially since Vector.toList is super cheap |
| 2025-12-16 11:11:06 | <merijn> | So someone wanting to pass a vector can easily convert to a list on demand |
| 2025-12-16 11:12:54 | <haskellbridge> | <loonycyborg> There's also Seq, and Set and lots of other containers depending on your needs |
| 2025-12-16 11:13:17 | <probie> | Let's just cut out the middle man and pass the fold `data List a = forall b . List ((a -> b -> b) -> b -> b)` |
| 2025-12-16 11:13:24 | <dminuoso> | Maybe it depends a bit on your problem domain, but in one of our projects there's quite a bit of `pack/unpack`, `fromStrict/ToString` or even combinations going on. |
| 2025-12-16 11:13:43 | <dminuoso> | There's just so much impedance mismatching going on when interfacing with more than one library at a time. |
| 2025-12-16 11:13:54 | → | Pixi joins (~Pixi@user/pixi) |
| 2025-12-16 11:14:00 | <probie> | (to clarify, my above statement is a joke, since that meets even fewer use cases than a list) |
| 2025-12-16 11:14:03 | <dminuoso> | And those problems are exactly the same as the above vector/list problems. |
| 2025-12-16 11:14:11 | <haskellbridge> | <magic_rb> Sounds to me like things need to get more generic :) |
| 2025-12-16 11:14:31 | <dminuoso> | probie: Joke is on you, thats precisely what GHC does behind the scenes for you in a lot of places. |
| 2025-12-16 11:15:21 | <dminuoso> | Its what the whole build/foldr fusion works. |
| 2025-12-16 11:15:57 | <dminuoso> | Or is that what you were hinting at? |
| 2025-12-16 11:18:48 | × | ljdarj quits (~Thunderbi@user/ljdarj) (Read error: Connection reset by peer) |
| 2025-12-16 11:20:03 | → | xff0x joins (~xff0x@2405:6580:b080:900:4560:111e:4edd:d178) |
| 2025-12-16 11:23:05 | → | wootehfoot joins (~wootehfoo@user/wootehfoot) |
| 2025-12-16 11:28:13 | × | merijn quits (~merijn@77.242.116.146) (Ping timeout: 264 seconds) |
| 2025-12-16 11:28:27 | × | wootehfoot quits (~wootehfoo@user/wootehfoot) (Quit: Leaving) |
| 2025-12-16 11:35:23 | trickard_ | is now known as trickard |
| 2025-12-16 11:39:40 | × | Maxdamantus quits (~Maxdamant@user/maxdamantus) (Ping timeout: 255 seconds) |
All times are in UTC.