Mutual scoping question

Hello, Cafe: Is there a preferred way to define two top-level mutually recursive functions, f and g, that both use a common local function h such that h is (1) only defined once and (2) does not escape the scope of f and g? I suppose it could be done like this: fg = let f ... = ... f,g,h ... g ... = ... f,g,h ... h ... = ... h ... in (f,g) f = fst fg g = snd fg but is there something more elegant than this that I'm not seeing? Todd Wilson

What about
let h ... = ... h ...in let f ... = ... f,g,h ... g ... = ... f,g,h ... in ... (main body that uses f and g) ...
This makes the dependencies clear. h stands on its own, f and g use each other together with h, and the main body can use f, g, and h.
I believe what you wanted, however, was to express that the main body *cannot* (will not, should not) use h. This version does not express that. On Wednesday, November 22, 2023 at 07:40:25 PM EST, Todd Wilson

Thanks, Mark. I wanted f and g to be defined at the top level for use
throughout my whole file, rather just inside of a let. Of course, I could
also put the definitions of f, g, and h in their own module/file that hides
the name h and then import this, but I was hoping to have this all in
one place.
--Todd
On Wed, Nov 22, 2023 at 5:26 PM Mark McConnell
What about
let h ... = ... h ... in let f ... = ... f,g,h ... g ... = ... f,g,h ... in ... (main body that uses f and g) ...
This makes the dependencies clear. h stands on its own, f and g use each other together with h, and the main body can use f, g, and h.
I believe what you wanted, however, was to express that the main body *cannot* (will not, should not) use h. This version does not express that. On Wednesday, November 22, 2023 at 07:40:25 PM EST, Todd Wilson < twilson@csufresno.edu> wrote:
Hello, Cafe:
Is there a preferred way to define two top-level mutually recursive functions, f and g, that both use a common local function h such that h is (1) only defined once and (2) does not escape the scope of f and g? I suppose it could be done like this:
fg = let f ... = ... f,g,h ... g ... = ... f,g,h ... h ... = ... h ... in (f,g) f = fst fg g = snd fg
but is there something more elegant than this that I'm not seeing?
Todd Wilson _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Can you do: (f, g) = let f’ = … in (f’, g’) or is a pattern match not allowed at top level? Jeff
On Nov 22, 2023, at 4:40 PM, Todd Wilson
wrote: Hello, Cafe:
Is there a preferred way to define two top-level mutually recursive functions, f and g, that both use a common local function h such that h is (1) only defined once and (2) does not escape the scope of f and g? I suppose it could be done like this:
fg = let f ... = ... f,g,h ... g ... = ... f,g,h ... h ... = ... h ... in (f,g) f = fst fg g = snd fg
but is there something more elegant than this that I'm not seeing?
Todd Wilson _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

It seems (surprisingly to me) that such pattern matches are allowed at the
top level, so that would simplify my kludge a bit by skipping the
definition of fg. But is using pairs (or the equivalent) in this way the
only solution? I was hoping that there might be some kind of top-level
definition syntax like
{f .. = ... ; g .. = ...} where h .. = ...
that would correctly capture the scoping I'm looking for.
--Todd
On Wed, Nov 22, 2023 at 5:43 PM Jeff Clites
Can you do:
(f, g) = let f’ = … in (f’, g’)
or is a pattern match not allowed at top level?
Jeff
On Nov 22, 2023, at 4:40 PM, Todd Wilson
wrote: Hello, Cafe:
Is there a preferred way to define two top-level mutually recursive functions, f and g, that both use a common local function h such that h is (1) only defined once and (2) does not escape the scope of f and g? I suppose it could be done like this:
fg = let f ... = ... f,g,h ... g ... = ... f,g,h ... h ... = ... h ... in (f,g) f = fst fg g = snd fg
but is there something more elegant than this that I'm not seeing?
Todd Wilson _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

SML has
local
declarations
in
declarations
end
and there is no fundamental reason why Haskell couldn't.
Is there some reason why you cannot put f g and h in a module and just
export f and g?
On Thu, 23 Nov 2023 at 16:42, Todd Wilson
It seems (surprisingly to me) that such pattern matches are allowed at the top level, so that would simplify my kludge a bit by skipping the definition of fg. But is using pairs (or the equivalent) in this way the only solution? I was hoping that there might be some kind of top-level definition syntax like
{f .. = ... ; g .. = ...} where h .. = ...
that would correctly capture the scoping I'm looking for.
--Todd
On Wed, Nov 22, 2023 at 5:43 PM Jeff Clites
wrote: Can you do:
(f, g) = let f’ = … in (f’, g’)
or is a pattern match not allowed at top level?
Jeff
On Nov 22, 2023, at 4:40 PM, Todd Wilson
wrote: Hello, Cafe:
Is there a preferred way to define two top-level mutually recursive functions, f and g, that both use a common local function h such that h is (1) only defined once and (2) does not escape the scope of f and g? I suppose it could be done like this:
fg = let f ... = ... f,g,h ... g ... = ... f,g,h ... h ... = ... h ... in (f,g) f = fst fg g = snd fg
but is there something more elegant than this that I'm not seeing?
Todd Wilson _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

I hope I am not misunderstanding the question, but if you want to define f, g and h, but only export f and g, this is what you would do in Haskell:
module Foo.Bar (f, g) where
f = ...
g = ...
h = ...
The module header determines what gets exported.
On Tuesday, November 28th, 2023 at 07:35, Richard O'Keefe
SML has local declarations in declarations end and there is no fundamental reason why Haskell couldn't. Is there some reason why you cannot put f g and h in a module and just export f and g?
On Thu, 23 Nov 2023 at 16:42, Todd Wilson twilson@csufresno.edu wrote:
It seems (surprisingly to me) that such pattern matches are allowed at the top level, so that would simplify my kludge a bit by skipping the definition of fg. But is using pairs (or the equivalent) in this way the only solution? I was hoping that there might be some kind of top-level definition syntax like
{f .. = ... ; g .. = ...} where h .. = ...
that would correctly capture the scoping I'm looking for.
--Todd
On Wed, Nov 22, 2023 at 5:43 PM Jeff Clites jclites@mac.com wrote:
Can you do:
(f, g) = let f’ = … in (f’, g’)
or is a pattern match not allowed at top level?
Jeff
On Nov 22, 2023, at 4:40 PM, Todd Wilson twilson@csufresno.edu wrote:
Hello, Cafe:
Is there a preferred way to define two top-level mutually recursive functions, f and g, that both use a common local function h such that h is (1) only defined once and (2) does not escape the scope of f and g? I suppose it could be done like this:
fg = let f ... = ... f,g,h ... g ... = ... f,g,h ... h ... = ... h ... in (f,g) f = fst fg g = snd fg
but is there something more elegant than this that I'm not seeing?
Todd Wilson _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

I mentioned earlier wanting to avoid modules for this, and hoping for something like the SML syntax that Richard mentioned, even making my own equivalent syntactic proposal {f = ...; g = ...} where h = ... which looks in line with current Haskell conventions. Given the existing options, however, I would probably go with a top-level pair definition: (f,g) = (..., ...) where h = ... or (f,g) = let f' = ...; g' = ...' ; h = ... in (f',g') as mentioned by Jeff. Thanks to all who contributed! --Todd On Tue, Nov 28, 2023 at 12:40 AM Daniel Casanueva < daniel.casanueva@proton.me> wrote:
I hope I am not misunderstanding the question, but if you want to define f, g and h, but only export f and g, this is what you would do in Haskell:
module Foo.Bar (f, g) where
f = ... g = ... h = ...
The module header determines what gets exported.
On Tuesday, November 28th, 2023 at 07:35, Richard O'Keefe < raoknz@gmail.com> wrote:
SML has local declarations in declarations end and there is no fundamental reason why Haskell couldn't. Is there some reason why you cannot put f g and h in a module and just export f and g?
On Thu, 23 Nov 2023 at 16:42, Todd Wilson twilson@csufresno.edu wrote:
It seems (surprisingly to me) that such pattern matches are allowed at
the top level, so that would simplify my kludge a bit by skipping the definition of fg. But is using pairs (or the equivalent) in this way the only solution? I was hoping that there might be some kind of top-level definition syntax like
{f .. = ... ; g .. = ...} where h .. = ...
that would correctly capture the scoping I'm looking for.
--Todd
On Wed, Nov 22, 2023 at 5:43 PM Jeff Clites jclites@mac.com wrote:
Can you do:
(f, g) = let f’ = … in (f’, g’)
or is a pattern match not allowed at top level?
Jeff
On Nov 22, 2023, at 4:40 PM, Todd Wilson twilson@csufresno.edu
wrote:
Hello, Cafe:
Is there a preferred way to define two top-level mutually recursive
functions, f and g, that both use a common local function h such that h is (1) only defined once and (2) does not escape the scope of f and g? I suppose it could be done like this:
fg = let f ... = ... f,g,h ... g ... = ... f,g,h ... h ... = ... h ... in (f,g) f = fst fg g = snd fg
but is there something more elegant than this that I'm not seeing?
Todd Wilson _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

On Tue, Nov 28, 2023 at 07:54:52AM -0800, Todd Wilson wrote:
I mentioned earlier wanting to avoid modules for this, and hoping for something like the SML syntax that Richard mentioned, even making my own equivalent syntactic proposal
{f = ...; g = ...} where h = ...
which looks in line with current Haskell conventions. Given the existing options, however, I would probably go with a top-level pair definition:
(f,g) = (..., ...) where h = ...
or
(f,g) = let f' = ...; g' = ...' ; h = ... in (f',g')
as mentioned by Jeff. Thanks to all who contributed!
Or, with heavy artilery, that I rather expect entirely optimises away: {-# LANGUAGE DataKinds, GADTs, LambdaCase, StandaloneKindSignatures, TypeFamilies #-} module Demo(f, g) where import Data.Kind (Type) type FG :: Bool -> Type type family FG b where FG False = String -> Bool FG True = Int -> String data SBool b where SFalse :: SBool False STrue :: SBool True f :: String -> Bool f = fg SFalse g :: Int -> String g = fg STrue fg :: SBool b -> FG b fg = \ case SFalse -> f' STrue -> g' where h :: Int -> String h = show f' s = s == h 0 g' i = h (i + 1) {-# INLINE fg #-} The "Core" output shows: -- RHS size: {terms: 15, types: 14, coercions: 0, joins: 0/0} g :: Int -> String g = \ (i :: Int) -> case i of { I# x -> case $wshowSignedInt 0# (+# x 1#) [] of { (# ww5, ww6 #) -> : ww5 ww6 } } -- RHS size: {terms: 9, types: 11, coercions: 0, joins: 0/0} f1 :: String f1 = case $wshowSignedInt 0# 0# [] of { (# ww5, ww6 #) -> : ww5 ww6 } -- RHS size: {terms: 4, types: 1, coercions: 0, joins: 0/0} f :: String -> Bool f = \ (s :: String) -> eqString s f1 -- Viktor.
participants (6)
-
Daniel Casanueva
-
Jeff Clites
-
Mark McConnell
-
Richard O'Keefe
-
Todd Wilson
-
Viktor Dukhovni