possible bug in default module lookup scheme / or invalid haskell?

Hello All, I'm not sure if this either a bug in how ghc does path/module lookup or it simply is invalid haskell: consider modules A, A.B and A.B.C where A imports A.B, and A.B imports A.B.C with the following file system layout A.hs A/B.hs A/B/C.hs minimal file examples: module A where import A.B testA = "will it really really work? ------------ module A.B where import A.B.C testB = "will it work ----------------- module A.B.C where testC = "will this work?" ---------- if i run ghci A.hs everything's fine but if in directory B i rune ghci B.hs, i get A/B.hs:2:8: Could not find module `A.B.C': Use -v to see a list of the files searched for. ----------- it seems to me that if the default search path for ghc(i) includes the current directory (which according to docs it does), this shouldn't be happening. (or is there some why this is good Behavior?) thanks! -Carter

Carter Schonwald
Hello All, I'm not sure if this either a bug in how ghc does path/module lookup or it simply is invalid haskell:
consider modules A, A.B and A.B.C where A imports A.B, and A.B imports A.B.C with the following file system layout
A.hs A/B.hs A/B/C.hs
minimal file examples: module A where import A.B testA = "will it really really work? ------------ module A.B where import A.B.C testB = "will it work ----------------- module A.B.C where testC = "will this work?" ---------- if i run ghci A.hs everything's fine but if in directory B i rune ghci B.hs, i get A/B.hs:2:8: Could not find module `A.B.C': Use -v to see a list of the files searched for.
----------- it seems to me that if the default search path for ghc(i) includes the current directory (which according to docs it does), this shouldn't be happening. (or is there some why this is good Behavior?)
I think ghci is just not smart enough to know that it should change to the parent directory and run it from there. As such, it's trying to find "A.B.C" from the context of the current directory, and the file is not in A/A/B/C.hs so it can't find it. So it's just a limitation of ghci (I think). -- Ivan Lazar Miljenovic Ivan.Miljenovic@gmail.com IvanMiljenovic.wordpress.com

Ivan Lazar Miljenovic wrote:
I think ghci is just not smart enough to know that it should change to the parent directory and run it from there. As such, it's trying to find "A.B.C" from the context of the current directory, and the file is not in A/A/B/C.hs so it can't find it.
So it's just a limitation of ghci (I think).
http://hackage.haskell.org/trac/ghc/ticket/3140 is almost exactly the same thing.

On Sat, 17 Jul 2010 22:45:57 -0700, Ivan Lazar Miljenovic
Carter Schonwald
writes: Hello All, I'm not sure if this either a bug in how ghc does path/module lookup or it simply is invalid haskell:
consider modules A, A.B and A.B.C where A imports A.B, and A.B imports A.B.C with the following file system layout
A.hs A/B.hs A/B/C.hs
minimal file examples: module A where import A.B testA = "will it really really work? ------------ module A.B where import A.B.C testB = "will it work ----------------- module A.B.C where testC = "will this work?" ---------- if i run ghci A.hs everything's fine but if in directory B i rune ghci B.hs, i get A/B.hs:2:8: Could not find module `A.B.C': Use -v to see a list of the files searched for.
----------- it seems to me that if the default search path for ghc(i) includes the current directory (which according to docs it does), this shouldn't be happening. (or is there some why this is good Behavior?)
I think ghci is just not smart enough to know that it should change to the parent directory and run it from there. As such, it's trying to find "A.B.C" from the context of the current directory, and the file is not in A/A/B/C.hs so it can't find it.
So it's just a limitation of ghci (I think).
I'm afraid I disagree and would view this as expected behavior. "import A.B.C" translates internally to something like load_file_using_paths("A/B/C.hs"). When you are running this from the top level directory (e.g. "top"), ghci includes the current path "top" so the lookup is for "top/A/B/C.hs", which clearly exists. When you are in directory B, ghci includes the current path "top/A/B" so the lookup is for "top/A/B/A/B/C.hs"... which does not exist, thus your error. Your example would require ghci to try load_file_using_paths("B/C.hs") (and then load_file_using_paths("C.hs") to be complete), which discards the directory heirarchy specified by the module nomenclature. This is not adviseable because it introduces ambiguities. For example, if you also had a C.hs in A and another C.hs in A/B, which C.hs should it load when you say "import A.B.C"? Or "import C"? If ghc/ghci discarded paths, then the results would be either (1) a different C.hs depending on your current directory, (2) the bottom-most C.hs, (3) the C.hs in the current directory, (4) random?. Worse, any of the above results in a trojan-horse style security hole. Also, what if there was a C.hs in the directory above you (top/..)? A 1:1 mapping between module heirarchy specification and directory paths is the only dependable mechanism. The better solution is to specifically set the paths you expect to form the roots of the (non-default) module heirarchy if you plan to work from within subdirectories of your source tree. If you invoked ghci as "$ ghci -i /path/to/top" then it would work regardless of your current directory. I believe that this is the proper solution to http://hackage.haskell.org/trac/ghc/ticket/3140 as well. -KQ -- -KQ

Hrm... my example also makes ghc flub too I think... (its been a long day).
is there anything implicitly going on behind this behavior that couldn't be
resolved by eg having the reasonable heuristic that for a module named *(Prefix
...).Name* in file *Name*, any import of the form* (Prefix ...).Blah* that
isn't a registered module should be searched for relative to the directory
containing the file *Name*? Ie, given a module A.B in directory A, the
prefix would be A, and thus we are looking for a module B.C relative to the
offset of Directory A/. This doesn't seem to be create any ambiguity, it
just more intelligently uses explicitly available in the source
information.
I don't think that semantics creates the sort of ambiguity that Kevin is
concerned about, and while yes there simple alternative approaches, they
require whatever is starting up ghci to know what the correct directory to
pass to the -i flag, and that seems a bit of a heavy weight expectation for
anything that can't apriori parse haskell modules (which would seem ironic
considering such tools typically use ghc's libraries for that task!)
*
*
On Sun, Jul 18, 2010 at 3:22 AM, Kevin Quick
On Sat, 17 Jul 2010 22:45:57 -0700, Ivan Lazar Miljenovic < ivan.miljenovic@gmail.com> wrote:
Carter Schonwald
writes: Hello All, I'm not sure if this either a bug in how ghc does path/module
lookup or it simply is invalid haskell:
consider modules A, A.B and A.B.C where A imports A.B, and A.B imports A.B.C with the following file system layout
A.hs A/B.hs A/B/C.hs
minimal file examples: module A where import A.B testA = "will it really really work? ------------ module A.B where import A.B.C testB = "will it work ----------------- module A.B.C where testC = "will this work?" ---------- if i run ghci A.hs everything's fine but if in directory B i rune ghci B.hs, i get A/B.hs:2:8: Could not find module `A.B.C': Use -v to see a list of the files searched for.
----------- it seems to me that if the default search path for ghc(i) includes the current directory (which according to docs it does), this shouldn't be happening. (or is there some why this is good Behavior?)
I think ghci is just not smart enough to know that it should change to the parent directory and run it from there. As such, it's trying to find "A.B.C" from the context of the current directory, and the file is not in A/A/B/C.hs so it can't find it.
So it's just a limitation of ghci (I think).
I'm afraid I disagree and would view this as expected behavior.
"import A.B.C" translates internally to something like load_file_using_paths("A/B/C.hs").
When you are running this from the top level directory (e.g. "top"), ghci includes the current path "top" so the lookup is for "top/A/B/C.hs", which clearly exists.
When you are in directory B, ghci includes the current path "top/A/B" so the lookup is for "top/A/B/A/B/C.hs"... which does not exist, thus your error.
Your example would require ghci to try load_file_using_paths("B/C.hs") (and then load_file_using_paths("C.hs") to be complete), which discards the directory heirarchy specified by the module nomenclature. This is not adviseable because it introduces ambiguities. For example, if you also had a C.hs in A and another C.hs in A/B, which C.hs should it load when you say "import A.B.C"? Or "import C"? If ghc/ghci discarded paths, then the results would be either (1) a different C.hs depending on your current directory, (2) the bottom-most C.hs, (3) the C.hs in the current directory, (4) random?. Worse, any of the above results in a trojan-horse style security hole. Also, what if there was a C.hs in the directory above you (top/..)? A 1:1 mapping between module heirarchy specification and directory paths is the only dependable mechanism.
The better solution is to specifically set the paths you expect to form the roots of the (non-default) module heirarchy if you plan to work from within subdirectories of your source tree. If you invoked ghci as "$ ghci -i /path/to/top" then it would work regardless of your current directory. I believe that this is the proper solution to http://hackage.haskell.org/trac/ghc/ticket/3140 as well.
-KQ
-- -KQ

On Sun, Jul 18, 2010 at 3:59 AM, Carter Schonwald
I don't think that semantics creates the sort of ambiguity that Kevin is concerned about, and while yes there simple alternative approaches, they require whatever is starting up ghci to know what the correct directory to pass to the -i flag, and that seems a bit of a heavy weight expectation
I usually use ghci's :cd command in this situation, and wouldn't want to think about changing source files depending on where they were on disk. While having to use fully hierarchical names might seem verbose, I have found it to be a very predictable mechanism that makes managing large-ish projects easier. Anthony

I'm not sure I follow, because the toy example I'm asking about does in fact
use hierarchical module names...
are you proposing that a reasonable workaround in my use case is to do
:cd ..
:r
this seems like a reasonableish approach, or was there a different example
you had in mind?
On Sun, Jul 18, 2010 at 1:34 PM, Anthony Cowley
On Sun, Jul 18, 2010 at 3:59 AM, Carter Schonwald
wrote: I don't think that semantics creates the sort of ambiguity that Kevin is concerned about, and while yes there simple alternative approaches, they require whatever is starting up ghci to know what the correct directory to pass to the -i flag, and that seems a bit of a heavy weight expectation
I usually use ghci's :cd command in this situation, and wouldn't want to think about changing source files depending on where they were on disk.
While having to use fully hierarchical names might seem verbose, I have found it to be a very predictable mechanism that makes managing large-ish projects easier.
Anthony _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Sun, Jul 18, 2010 at 1:55 PM, Carter Schonwald
I'm not sure I follow, because the toy example I'm asking about does in fact use hierarchical module names... are you proposing that a reasonable workaround in my use case is to do :cd .. :r this seems like a reasonableish approach, or was there a different example you had in mind?
Yes, that is what I had in mind. The typical scenario for me is to be editing a file in emacs, C-c-C-l it, and have GHCi complain. I then issue a ":cd .." in GHCi, and my subsequent loads are properly rooted at top of the project directory. What I was trying to describe as unwanted is for someone to take your toy example and, in the file A/B.hs have a line "import B.C" that is gets correctly resolved by GHC. I'm not sure that you were actually suggesting this, but this kind of leniency on the part of GHC (or GHCi) would make the file B.hs fragile with respect to moving it around on disk. Anthony
On Sun, Jul 18, 2010 at 1:34 PM, Anthony Cowley
wrote: On Sun, Jul 18, 2010 at 3:59 AM, Carter Schonwald
wrote: I don't think that semantics creates the sort of ambiguity that Kevin is concerned about, and while yes there simple alternative approaches, they require whatever is starting up ghci to know what the correct directory to pass to the -i flag, and that seems a bit of a heavy weight expectation
I usually use ghci's :cd command in this situation, and wouldn't want to think about changing source files depending on where they were on disk.
While having to use fully hierarchical names might seem verbose, I have found it to be a very predictable mechanism that makes managing large-ish projects easier.
Anthony _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

nope, I was suggesting rather:
./A.hs has module A which has an import A.B line
./A/ has B.hs with module A.B which imports A.B.C
/C which has module A.B.C in file C.hs
I think this scenario should work ....
-carter
On Sun, Jul 18, 2010 at 2:18 PM, Anthony Cowley
On Sun, Jul 18, 2010 at 1:55 PM, Carter Schonwald
wrote: I'm not sure I follow, because the toy example I'm asking about does in fact use hierarchical module names... are you proposing that a reasonable workaround in my use case is to do :cd .. :r this seems like a reasonableish approach, or was there a different example you had in mind?
Yes, that is what I had in mind. The typical scenario for me is to be editing a file in emacs, C-c-C-l it, and have GHCi complain. I then issue a ":cd .." in GHCi, and my subsequent loads are properly rooted at top of the project directory.
What I was trying to describe as unwanted is for someone to take your toy example and, in the file A/B.hs have a line "import B.C" that is gets correctly resolved by GHC. I'm not sure that you were actually suggesting this, but this kind of leniency on the part of GHC (or GHCi) would make the file B.hs fragile with respect to moving it around on disk.
Anthony
On Sun, Jul 18, 2010 at 1:34 PM, Anthony Cowley
wrote: On Sun, Jul 18, 2010 at 3:59 AM, Carter Schonwald
wrote: I don't think that semantics creates the sort of ambiguity that Kevin
concerned about, and while yes there simple alternative approaches,
require whatever is starting up ghci to know what the correct
is they directory
to pass to the -i flag, and that seems a bit of a heavy weight expectation
I usually use ghci's :cd command in this situation, and wouldn't want to think about changing source files depending on where they were on disk.
While having to use fully hierarchical names might seem verbose, I have found it to be a very predictable mechanism that makes managing large-ish projects easier.
Anthony _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Sun, 18 Jul 2010 12:02:39 -0700, Carter Schonwald
nope, I was suggesting rather: ./A.hs has module A which has an import A.B line ./A/ has B.hs with module A.B which imports A.B.C /C which has module A.B.C in file C.hs
I think this scenario should work .... -carter
It's an interesting proposal, but unfortunately there's the possibility of an n:1 mapping between parent directory and child. This would make using ".." against the current working directory potentially non-deterministic, and removing lower elements from an absolute path wouldn't necessarily get you back to the directory where A.hs lived either. -- -KQ

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 7/18/10 14:18 , Anthony Cowley wrote:
On Sun, Jul 18, 2010 at 1:55 PM, Carter Schonwald
wrote: are you proposing that a reasonable workaround in my use case is to do :cd .. :r this seems like a reasonableish approach, or was there a different example you had in mind?
Yes, that is what I had in mind. The typical scenario for me is to be editing a file in emacs, C-c-C-l it, and have GHCi complain. I then issue a ":cd .." in GHCi, and my subsequent loads are properly rooted at top of the project directory.
The fundamental problem is that ghci has no concept of "projects". The correct place for this is in Cabal, which *does* have project support, but as yet it has no support for ghci. It's conceivable that the ghci user commands capability could be used to find (and optionally) parse a *.cabal file to identify a package root, at the price of an initial slowdown if you didn't have one. - -- brandon s. allbery [linux,solaris,freebsd,perl] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.10 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkxDXB0ACgkQIn7hlCsL25WqagCg1Z9yJunJObDQWj27awIjZgNF 420AoNFoW3O75O1VOOP7lzXOVW7iMtjZ =jaTS -----END PGP SIGNATURE-----

begin Brandon S Allbery KF8NH quotation:
The fundamental problem is that ghci has no concept of "projects". The correct place for this is in Cabal, which *does* have project support, but as yet it has no support for ghci. It's conceivable that the ghci user commands capability could be used to find (and optionally) parse a *.cabal file to identify a package root, at the price of an initial slowdown if you didn't have one.
Not sure if anyone mentioned this possibility elsewhere in the thread, but I was thinking that having a "cabal console" command would be a nice way to handle this. Cabal would parse the *.cabal file and invoke ghci with the appropriate incantation. -d

Silly question, but I can't find the answer on the net. I think I'm just using the wrong words in my search. I'm looking for a way to create constant expressions in Haskell. The C/C++ equivalent of what I'm talking about is #define NAME VALUE I want an expression, or really just numbers for what I'm doing, that the compiler will put into the program at the designated places, instead of storing it in memory like a variable. -Eitan

On Sunday 18 July 2010 22:19:21, Eitan Goldshtrom wrote:
Silly question, but I can't find the answer on the net. I think I'm just using the wrong words in my search. I'm looking for a way to create constant expressions in Haskell. The C/C++ equivalent of what I'm talking about is
#define NAME VALUE
I want an expression, or really just numbers for what I'm doing, that the compiler will put into the program at the designated places, instead of storing it in memory like a variable.
-Eitan
Just make a top-level definition name = value and if you want to make sure it's inlined, {-# INLINE name #-} Or you can use {-# LANGUAGE CPP #-} with the #define

On Sun, Jul 18, 2010 at 5:19 PM, Eitan Goldshtrom
Silly question, but I can't find the answer on the net. I think I'm just using the wrong words in my search. I'm looking for a way to create constant expressions in Haskell. The C/C++ equivalent of what I'm talking about is
#define NAME VALUE
I want an expression, or really just numbers for what I'm doing, that the compiler will put into the program at the designated places, instead of storing it in memory like a variable.
Unless you want to pattern match the value, just say myconst :: Double -- or anything else myconst = 7.14 {-# INLINE myconst #-} Voilà! This doesn't work for pattern matching, however, if you say f myconst = ... then 'myconst' will be the name of that argument that could be anything, and not just 7.14. You could, however, use CPP as well {-# LANGUAGE CPP #-} #define MYCONST 7.14 f MYCONST = ... but I'm against using CPP unless you need it. Cheers, -- Felipe.

On Sun, Jul 18, 2010 at 10:19 PM, Eitan Goldshtrom
Silly question, but I can't find the answer on the net. I think I'm just using the wrong words in my search. I'm looking for a way to create constant expressions in Haskell. The C/C++ equivalent of what I'm talking about is
#define NAME VALUE
NAME = VALUE the inliner should easily take care of it, if VALUE is a constant. Note that in the designation above, NAME will *be* a constant value due to the functional aspect of Haskell (it can't change later on). You need the discrimination in C because something like int NAME = VALUE; defines a global variable, which may change and hence cannot be inlined. -- J.

So just so I get this straight, the following are equivalent to the computer, after compiling: 1. fact = 10 {-# INLINE fact #-} func x = x * fact 2. func x = x * 10 I'm also curious as to what the {-# #-} brackets represent. I've never seen those before. -Eitan

On Sunday 18 July 2010 23:07:38, Eitan Goldshtrom wrote:
So just so I get this straight, the following are equivalent to the computer, after compiling:
1. fact = 10 {-# INLINE fact #-}
func x = x * fact
2. func x = x * 10
I'm not sure if they're equivalent when compiled without optimisations, but with optimisations, they ought to. Actually, with optimisations, the inline-pragma shouldn't even be necessary.
I'm also curious as to what the {-# #-} brackets represent. I've never seen those before.
They mark pragmas, there are a lot of useful pragmas in GHC, take a look at the user's guide, section 7.
-Eitan

One point of clarification that'd be nice. I'm getting some type errors that I wasn't getting before, so I'd just like to know something about the inline pragma. I have width = 800 {-# INLINE width #-} main = (truncate width, fromIntegral width) Now when I ran this program it seemed to work at first. Note that truncate and fromIntegral take different types as inputs. I then changed a different part of the program having nothing to do with this code and all of a sudden GHC started giving me a type error about the above code. Does anyone know why? -Eitan

Correction to my last e-mail. I figured out why it worked at first and then failed, so I'll refine my question. I'd like the compiler to simply put the number 800 everywhere that I put the name "width" in my code. Instead it's putting (800 :: Float), or Double or Int, whatever I want, but it's restricted to one data type. I want to remove that restriction since it is a constant. -Eitan

Eitan Goldshtrom
Correction to my last e-mail. I figured out why it worked at first and then failed, so I'll refine my question. I'd like the compiler to simply put the number 800 everywhere that I put the name "width" in my code. Instead it's putting (800 :: Float), or Double or Int, whatever I want, but it's restricted to one data type. I want to remove that restriction since it is a constant.
It _might_ work by having an explicit type signature for it: width :: (Num a) => a width = 800 But I think it will get defaulted to something. -- Ivan Lazar Miljenovic Ivan.Miljenovic@gmail.com IvanMiljenovic.wordpress.com

Use NoMonomorphismRestriction or give an explicit type signature:
width :: Num a => a
width = 800
Max
On 19 July 2010 09:17, Eitan Goldshtrom
Correction to my last e-mail. I figured out why it worked at first and then failed, so I'll refine my question. I'd like the compiler to simply put the number 800 everywhere that I put the name "width" in my code. Instead it's putting (800 :: Float), or Double or Int, whatever I want, but it's restricted to one data type. I want to remove that restriction since it is a constant.
-Eitan _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Awesome. It worked. Haskell continues to impress me. Thanks for the help everyone. -Eitan On 7/19/2010 4:42 AM, Max Bolingbroke wrote:
Use NoMonomorphismRestriction or give an explicit type signature:
width :: Num a => a width = 800
Max

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 7/18/10 16:10 , Mike Dillon wrote:
Not sure if anyone mentioned this possibility elsewhere in the thread, but I was thinking that having a "cabal console" command would be a nice way to handle this. Cabal would parse the *.cabal file and invoke ghci with the appropriate incantation.
There's an open feature request for "cabal ghci" (http://hackage.haskell.org/trac/hackage/ticket/382); unfortunately, it's not quite as trivial as it first looks. I actually considered putting together a quick cabal-ghci for local use, but quickly realized that for most of the cases where I would want to use it it would actually be pretty hairy to get right. - -- brandon s. allbery [linux,solaris,freebsd,perl] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.10 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkxDZKwACgkQIn7hlCsL25VMwQCfe73MZuYQqEWQnWFWozJNy9BS XegAnROscy3D0G+ng3Q3OuOVuBpbzgjC =gIoL -----END PGP SIGNATURE-----
participants (12)
-
Andrew Coppin
-
Anthony Cowley
-
Brandon S Allbery KF8NH
-
Carter Schonwald
-
Daniel Fischer
-
Eitan Goldshtrom
-
Felipe Lessa
-
Ivan Lazar Miljenovic
-
Jesper Louis Andersen
-
Kevin Quick
-
Max Bolingbroke
-
Mike Dillon