2026/02/25

Newest at the top

2026-02-25 18:45:54 +0100 <__monty__> I love Agda's approach to scoping, https://agda.readthedocs.io/en/latest/language/module-system.html
2026-02-25 18:45:20 +0100tromp(~textual@2001:1c00:3487:1b00:7955:9591:6018:7ef9)
2026-02-25 18:45:16 +0100 <ski> (.. sometimes i also want to use `if' or `case', at declaration level. `if ... then {f x = ...; g y z = ...} else {f x = ...; g y z = ...}'. having declarations as the body of the branches, conditionally defining in one of several ways (all branches have to define the same identifiers, naturally))
2026-02-25 18:41:42 +0100 <ski> you never define local functions in a `where' or `let' ?
2026-02-25 18:41:22 +0100 <EvanR> I have to admit I'm a never nester
2026-02-25 18:40:01 +0100 <ski> (of course, you could simply hide, not export, `extraDef', from the module in question. but it's often nice to restrict scope more, to make sure it's evident that `extraDef' isn't used elsewhere in the module. and Haskell doesn't allow nested submodules ..)
2026-02-25 18:38:19 +0100fgarcia(~lei@user/fgarcia) fgarcia
2026-02-25 18:38:09 +0100emaczen(~user@user/emaczen) emaczen
2026-02-25 18:38:04 +0100 <ski> (`fun ... and ...' is mutual recursive functions)
2026-02-25 18:37:38 +0100 <ski> in SML, this would be `local fun extraDef ... = ... in fun foo ... = ... and bar ... = ... end'
2026-02-25 18:37:00 +0100 <ski> in Haskell, you often have to resort to `(foo,bar) = (myFoo,MyBar) where myFoo = ...; myBar = ...; extraDef = ...', for this, which is ugly
2026-02-25 18:36:10 +0100 <ski> a somewhat related thing is the `local <decls> in <decls> end' declaration, in SML. it declares the latter declarations (between `in' and `end'), while hiding the former ones, letting them be in scope in the latter ones, but not visible elsewhere
2026-02-25 18:35:05 +0100emaczen(~user@user/emaczen) (Remote host closed the connection)
2026-02-25 18:34:49 +0100 <ski> yea, that's too invasive
2026-02-25 18:34:19 +0100 <haskellbridge> <ijouw> Using current language, I would likely try to solve the dependency by making foo and bar a function and using liftA2 a lot and other pointfree stuff so cfg is never specified (but that will likely not make it readable).
2026-02-25 18:30:17 +0100uli-fem(~uli-fem@118.210.1.123) (Ping timeout: 248 seconds)
2026-02-25 18:30:14 +0100 <ski> (btw, it would perhaps look neater to say `foo where cfg = defaultCfg' in place of `let cfg = defaultCfg in foo' .. but `where' is not an expression, attaches to defining equations (and `case' branches))
2026-02-25 18:27:59 +0100skiprefers to pretend that extension does not exist
2026-02-25 18:27:37 +0100 <haskellbridge> <ijouw> After enabling OverloadedRecordDot my brain parses that weirdly
2026-02-25 18:27:08 +0100jmcantrell_(~weechat@user/jmcantrell) jmcantrell
2026-02-25 18:26:36 +0100 <ski> ijouw : yes (that's why i wrote `foo' and `bar' in `..?cfg..foo.bar..', to indicate that those three would be allowed to occur free in that body)
2026-02-25 18:25:59 +0100 <ski> nicer way to do it, but one would need to explain how `foo' could be in scope in the `barf' definition, and how `bar' could be in scope in the `frob' definition
2026-02-25 18:25:52 +0100 <ski> (c) sometimes you want to do (a), but for mutually recursive functions, wanting to avoid passing around the *same* identical prefix parameters. so, i was pondering how one could possibly effect that, with a minimum of fuss. one attempt was to locally bind the respective parameters to an implicit `?cfg' (implementation detail), and then use that for the local, mutually recursive, definitions. there might be a
2026-02-25 18:25:35 +0100uli-fem(~uli-fem@118.210.1.123)
2026-02-25 18:24:14 +0100 <haskellbridge> <ijouw> Do you intend foo = ..?cfg..foo..bar.. to be recursive?
2026-02-25 18:23:02 +0100 <ski> (b) sometimes you have a general version of a function, and one version specialized to passing some default value for a parameter, as exemplified by `fooWith' & `foo'. as indicated, this could be done with conjunctive patterns, and `let'-`in'-patterns
2026-02-25 18:21:05 +0100 <ski> explicit recursive call, passing some different value(s) for the prefix parameters, which would then bind the identifier (`loop') here to this *new* prefix, for that recursive call (this can e.g. be useful, if you're passing around an environment to an interpreter or type checker, mostly you want to pass along the same environment, but sometimes you want to change it)
2026-02-25 18:20:59 +0100 <ski> (a) the `loop' and `map' case would be a way to give a *local* name for the function you're defining, applied to some prefix of the formal parameters, so that you don't need to repeat those parameters at recursive calls. this abbreviated form would naturally only be in scope inside the definition, and not elsewhere (because we would not know which value `f' would be bound to). it would be possible to use an
2026-02-25 18:18:55 +0100merijn(~merijn@77.242.116.146) (Ping timeout: 245 seconds)
2026-02-25 18:16:50 +0100 <ski> this is about creative uses of patterns and scoping, to effect some convenience/elegance, for certain kinds of definition idioms
2026-02-25 18:15:19 +0100 <ski> (it's not clear whether by `f g' you mean an expression, or a pattern, btw ..)
2026-02-25 18:11:47 +0100 <ski> (this is not about dynamic scope)
2026-02-25 18:11:34 +0100 <ski> no
2026-02-25 18:10:37 +0100 <haskellbridge> <ijouw> You want (f g) to implicitly use another function named g that is in scope at use site?
2026-02-25 18:10:29 +0100 <ski> (for the `loop' & `map' case above, `loop' doesn't explicitly bind the `f' parameter (and so must already assume `f' already comes from somewhere), so `loop' would just be in scope in the body, and not be in scope elsewhere `map' is in scope (where `f' isn't). in the `fooWith' & `foo' case, both conjuncts does bind `cfg', so both `fooWith' and `foo' makes sense here to use in a scope where `cfg' is not bound)
2026-02-25 18:09:09 +0100sondr3(sondr3@2a01:7e01::f03c:92ff:fe06:7664)
2026-02-25 18:08:59 +0100sondr3(sondr3@2a01:7e01::f03c:92ff:fe06:7664) (Server closed connection)
2026-02-25 18:06:39 +0100 <ski> (issue is how to (reasonably) get both `foo' and `bar' in scope in both bodies ..)
2026-02-25 18:06:08 +0100 <ski> to express this ..
2026-02-25 18:06:01 +0100 <ski> bar@(barf cfg) = ..cfg..foo..bar..
2026-02-25 18:05:52 +0100 <ski> foo@(frob cfg) = ..cfg..foo..bar..
2026-02-25 18:05:31 +0100 <ski> maybe there's be some version of
2026-02-25 18:04:29 +0100 <ski> it would be nice to be able to say something like `(frob,barf) = (\ ?cfg -> foo,\ ?cfg -> bar) where foo :: (?cfg :: ...) => ...; foo = ..?cfg..foo..bar..; bar :: (?cfg :: ...) => ...; bar = ..?cfg..foo.bar..' (having a common "config" argument in scope, over mutual recursion, avoiding repeating it in the recursive calls)
2026-02-25 18:03:53 +0100lortabac(~lortabac@mx1.fracta.dev) lortabac
2026-02-25 18:03:39 +0100lortabac(~lortabac@mx1.fracta.dev) (Server closed connection)
2026-02-25 18:01:39 +0100misterfish(~misterfis@84.53.85.146) (Ping timeout: 246 seconds)
2026-02-25 17:59:41 +0100fgarcia(~lei@user/fgarcia) (Ping timeout: 268 seconds)
2026-02-25 17:58:21 +0100 <ski> where `let cfg = defaultCfg in foo' is a pattern that matches the input to `foo', and additionally binds `cfg' to `defaultCfg' (so that regardless of whether we use the `fooWith' or the `foo' entry point to the code, `cfg' will be in scope in the body)
2026-02-25 17:57:05 +0100 <ski> yes. the second `@' would be the generalization of and/conjunction-pattern
2026-02-25 17:56:31 +0100 <lambdabot> <hint>:1:32: error: Expression syntax in pattern: ?x