Home liberachat/#haskell: Logs Calendar

Logs: liberachat/#haskell

←Prev  Next→ 1,800,352 events total
2026-01-12 19:23:30 <Enrico63> > That said, while you can emulate the dynamic typing of pickle.load() if you really want to by deferring the type check until the last possible moment, the reality is that doing so is almost never actually useful. At some point, you have to make assumptions about the structure of the value in order to use it, and you know what those assumptions
2026-01-12 19:23:30 <Enrico63> are because you wrote the code. **While there are extremely rare exceptions to this that require true dynamic code loading (such as, say, implementing a REPL for your programming language), they do not occur in day-to-day programming, and programmers in statically-typed languages are perfectly happy to supply their assumptions up front.**
2026-01-12 19:23:31 <Enrico63> This paragraph is not representative of the whole post, which is about the idea that _static type systems are not fundamentally worse than dynamic type systems at processing data with an open or partially-known structure_; however, the highlighted portion of the paragraph I quoted just piques my curiosity about a different topic, which is "when is
2026-01-12 19:23:31 <lambdabot> <hint>:1:10: error: parse error on input `,'
2026-01-12 19:23:31 <Enrico63> a dynamic language (or a feature) really necessary?", and I'm curious as to why "implementing a REPL for your programming language" is such a case.
2026-01-12 19:23:50 × ezzieyguywuf quits (~Unknown@user/ezzieyguywuf) (Read error: Connection reset by peer)
2026-01-12 19:23:59 <Enrico63> Oh, forgot that the leading > has a meaning, sorry
2026-01-12 19:24:33 <Enrico63> I known the question is not about Haskell, but I assume many people in here can help me understand :/
2026-01-12 19:28:17 <dolio> Implementing a REPL basically by-definition requires that.
2026-01-12 19:28:29 <tomsmeding> Enrico63: if you implement a REPL, you genuinely have no assumptions about the values that the user might produce inside that REPL. So assuming that you represent those values somehow in the implementation of your REPL, you will be able to do no better than "it's a value"
2026-01-12 19:28:38 <dolio> Because you type code into a REPL and it gets dynamically loaded.
2026-01-12 19:29:11 <tomsmeding> I think this is what Alexis is getting at, in any case
2026-01-12 19:30:00 <tomsmeding> more concretely, if you implement an interpreter for a language, then how do you represent the values computed in the language you're interpreting?
2026-01-12 19:30:15 <tomsmeding> (I say "more concretely" because a REPL may well be compiled and not interpreted, like GHCi is)
2026-01-12 19:30:39 <tomsmeding> (though the boundary between "compiled" and "interpreted" is a bit fuzzy here)
2026-01-12 19:33:39 <Enrico63> Mmmmmmm. Say I have a language XYZ. And I tell that in XYZ you can write something like `eval("this is XYZ code")`. If this is possible, do you deduce that XYZ is necessarily a dynamically typed langauge?
2026-01-12 19:33:59 <EvanR> if you're implementing a REPL for a language with a static type system, it just means you need to be dynamically adding to the static type definitions, so future inputs can be parsed and checked
2026-01-12 19:34:17 <EvanR> the repl input is basically that eval (in some context)
2026-01-12 19:34:37 <EvanR> doesn't require dynamic typing at all
2026-01-12 19:34:42 <EvanR> see haskell
2026-01-12 19:35:29 <EvanR> ghci
2026-01-12 19:35:50 <tomsmeding> Enrico63: you can have a type with dynamic structure in a statically typed language: see aeson's Value
2026-01-12 19:36:09 <EvanR> also that though it didn't seem to be the subject of the post
2026-01-12 19:36:21 <tomsmeding> the "interpreter" example is an argument why you may not know what structure a particular type has, not that a statically-typed language is fundamentally unsuitable
2026-01-12 19:37:09 <tomsmeding> in this case, note that aeson's Value is an explicit data type in Haskell that forces you to announce that an object comes now (Object), or a string comes now (String), etc.
2026-01-12 19:37:32 <tomsmeding> whereas in a dynamically typed language, what was represented by that Value could simply be a nesting of objects and strings without intervening data constructors
2026-01-12 19:37:36 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-01-12 19:37:37 Lord_of_Life_ joins (~Lord@user/lord-of-life/x-2819915)
2026-01-12 19:37:52 <EvanR> interpreter for a language always has to parse its input before doing anything. If it's statically typed it means you have more checks after the parsing, this isn't that much of a fundamental difference between languages
2026-01-12 19:37:54 <tomsmeding> so for this very dynamic use case, we have to do a bit more work in a statically-typed language than we do in a dynamically-typed language
2026-01-12 19:38:11 × trickard quits (~trickard@cpe-48-98-47-163.wireline.com.au) (Read error: Connection reset by peer)
2026-01-12 19:38:24 trickard_ joins (~trickard@cpe-48-98-47-163.wireline.com.au)
2026-01-12 19:38:25 × Lord_of_Life quits (~Lord@user/lord-of-life/x-2819915) (Ping timeout: 264 seconds)
2026-01-12 19:38:55 Lord_of_Life_ is now known as Lord_of_Life
2026-01-12 19:39:05 <tomsmeding> (notable side track: if the language you're interpreting is itself typed and the AST you're interpreting is type-indexed in haskell too, you can write a strongly-typed interpreter that doesn't need such "tags" (data constructors))
2026-01-12 19:39:16 <Enrico63> "if you implement an interpreter for a language, then how do you represent the values computed in the language you're interpreting?" Can you explain? It isn't obvious to me
2026-01-12 19:40:42 <EvanR> can I get a reaction to your eval question.
2026-01-12 19:40:46 <EvanR> > ord 'a'
2026-01-12 19:40:47 <lambdabot> 97
2026-01-12 19:40:55 <EvanR> > chr 'a'
2026-01-12 19:40:56 <lambdabot> Couldn't match expected type ‘Int’ with actual type ‘Char’
2026-01-12 19:40:56 <lambdabot> In the first argument of ‘chr’, namely ‘'a'’
2026-01-12 19:40:56 <lambdabot> In the expression: chr 'a'
2026-01-12 19:41:08 <EvanR> it's evalling the 'string' but it's not a dynamically typed language
2026-01-12 19:41:56 <EvanR> the string ord 'a'
2026-01-12 19:42:09 <Enrico63> What is the language under > ?
2026-01-12 19:42:29 × trickard_ quits (~trickard@cpe-48-98-47-163.wireline.com.au) (Read error: Connection reset by peer)
2026-01-12 19:42:31 <Enrico63> Haskell?
2026-01-12 19:42:37 × euphores quits (~SASL_euph@user/euphores) (Quit: Leaving.)
2026-01-12 19:42:48 <tomsmeding> Enrico63: https://play.haskell.org/saved/nOqh7N84 this is a little interpreter for a stupid little language that only has integers and pairs
2026-01-12 19:42:53 <Enrico63> Oh, ord is not in prelude, that's why I don't see it in ghci :D
2026-01-12 19:42:55 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 264 seconds)
2026-01-12 19:43:05 <EvanR> import Data.Char
2026-01-12 19:43:45 <tomsmeding> Enrico63: note Value in my snippet: to represent the value morally written "(2, 3)", I have to write "VPair (VI 2) (VI 3)"
2026-01-12 19:43:59 <Enrico63> Yeah, EvanR, yeah. Given what it is I thought it was in Prelude, but when I tried in ghci I got the error, and questioned myself why I was giving for granted it was Haskell.
2026-01-12 19:44:05 <tomsmeding> the VPair takes the place of the (,), but the VI are strictly extra compared to the "typed" representation "(2, 3)"
2026-01-12 19:44:58 <tomsmeding> this Value is quite dynamic: given a Value, we only know what grammar values follow, but inside that there may be anything
2026-01-12 19:45:16 <tomsmeding> it's not very "typed"
2026-01-12 19:46:11 <tomsmeding> in a dynamically typed language, there'd be no need for the VI as you'd just stuff integers in pairs and call it a day
2026-01-12 19:47:18 <EvanR> .oO( there could plausibly be a language where you don't need the VI but it's not dynamically typed )
2026-01-12 19:48:06 <tomsmeding> this dynamic/static typing is very much "I know it when I see it" terminology; it's hard to impossible (and probably unproductive) to give a strict definition, but particular languages are generally agreed to be either the one or the other
2026-01-12 19:48:33 trickard_ joins (~trickard@cpe-48-98-47-163.wireline.com.au)
2026-01-12 19:49:02 <tomsmeding> bonus treat: by making the embedded language strongly typed, we can remove some of the dynamism https://play.haskell.org/saved/a3yS25TF
2026-01-12 19:49:03 <EvanR> for a long time I felt the distinction comes down to not really the language itself but the workflow, your shit is checked immediately or at the last possible minute
2026-01-12 19:49:32 <tomsmeding> (note that the error cases in 'interpret' are gone!)
2026-01-12 19:50:10 <EvanR> for instance, elixir is very dynamic, but is currently being heavily checked in the IDE using what they're calling "a type system"
2026-01-12 19:50:21 <EvanR> so it's getting pretty similar in some way to a static language
2026-01-12 19:50:37 <EvanR> but it's the same language as before
2026-01-12 19:51:47 <tomsmeding> Enrico63: remember that Alexis' point was that you can simulate dynamic typing in a statically-typed language by deferring checks until the last possible moment (see my first 'interpret' function that errors at the last possible moment), and that you generally do _not_ want to do this except for the specific case of writing an interpreter
2026-01-12 19:51:56 euphores joins (~SASL_euph@user/euphores)
2026-01-12 19:52:07 <tomsmeding> her point was not that you must use a dynamically-typed language here
2026-01-12 19:53:24 <tomsmeding> that is: if you're parsing JSON with aeson, you generally *don't* want to parse to a Value ( https://hackage.haskell.org/package/aeson-2.2.3.0/docs/Data-Aeson.html#t:Value ) and deal with wrong keys/types later
2026-01-12 19:53:24 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-01-12 19:53:40 <tomsmeding> but exceptions to that "generally" exist, and an interpreter is one of them
2026-01-12 19:55:00 <tomsmeding> (is there a Rice's theorem for rules? Every rule that says something nontrivial has exceptions)
2026-01-12 19:55:43 <EvanR> someone's law: all rules have exceptions, including someone's law
2026-01-12 19:56:11 <tomsmeding> indeed, the trivial rules
2026-01-12 19:56:41 <tomsmeding> thus we conclude that all rules with no exceptions are trivial
2026-01-12 19:57:43 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 240 seconds)
2026-01-12 19:57:57 <Enrico63> I'm re-reading from the beginning :|
2026-01-12 20:00:37 × vanishingideal quits (~vanishing@user/vanishingideal) (Ping timeout: 264 seconds)
2026-01-12 20:00:57 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-01-12 20:03:35 × sp1ff quits (~user@2601:1c2:4701:900::327f) (Read error: Connection reset by peer)
2026-01-12 20:07:35 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 240 seconds)
2026-01-12 20:11:40 × Jackneill quits (~Jackneill@94-21-195-8.pool.digikabel.hu) (Read error: Connection reset by peer)
2026-01-12 20:11:42 Jackneill_ joins (~Jackneill@94-21-195-8.pool.digikabel.hu)
2026-01-12 20:13:25 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-01-12 20:17:11 <Enrico63> tomsmeding, I see that in the two code snippets you have an interpreter for a weakly vs strongly typed language. If nothing else, I can `interpret $ Plus (Pair (I 2) (I 3)) (I 4)`, which errors at runtime vs fails to compile. Understood. But when you write "this Value is quite dynamic: given a Value, we only know what grammar values follow, but
2026-01-12 20:17:11 <Enrico63> inside that there may be anything", what does that exactly mean? Is it that given a Value (in the first snippet) I have to match on constructors (something that happens at runtime), whereas Value (in the second snippet), being parametric carries information in its type?
2026-01-12 20:17:44 × spew quits (~spew@user/spew) (Quit: nyaa~)
2026-01-12 20:18:16 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 246 seconds)
2026-01-12 20:18:56 jmcantrell_ joins (~weechat@user/jmcantrell)
2026-01-12 20:19:38 × Googulator quits (~Googulato@2a01-036d-0106-4994-d043-6d2a-58f7-29ea.pool6.digikabel.hu) (Quit: Client closed)
2026-01-12 20:19:39 jzargo joins (~jzargo@user/jzargo)
2026-01-12 20:19:54 Googulator joins (~Googulato@2a01-036d-0106-4994-d043-6d2a-58f7-29ea.pool6.digikabel.hu)
2026-01-12 20:27:00 <tomsmeding> Enrico63: the second snippet is more of a side-note that muddles the waters in this discussion
2026-01-12 20:27:38 <tomsmeding> the point in the first snippet is that when interpreting 'Fst e', I have to pattern-match on the result of 'interpret e' to check if it is VPair or something else
2026-01-12 20:28:16 <Enrico63> Ok. I see that.
2026-01-12 20:28:33 <tomsmeding> this is a check at the last possible time: there is some kind of assumption on the shape of this value (because Fst requires a pair), but our data representation does not encode that assumption
2026-01-12 20:29:10 <tomsmeding> normally, in a statically typed language, we try to avoid this: when you use 'fst' in haskell, you'd rather like the type system to ensure that the argument to 'fst' is indeed a pair!

All times are in UTC.