1

I have the following in a module Util that I use widely without issues:

(>~) = flip fmap
infix 8 >~

(>>~) :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)
(>>~) = Control.Monad.forM
infix 8 >>~

(The explicit type sig is only because despite the bleedingly obvious "it's just an alias for a built-in func" GHC couldn't figure this out and forced me to, so let's ignore this here.)

NOW, in another module (same project) I import the above operators and oddly enough, the following few lines DO compile just-fine:

listAllFiles rootdirpath reldirs modtimer =
    let allfiles = (dirpaths >>~ foreachdir) >~~ concat
        (>~~) = flip fmap
        infix 8 >~~
        ...

But the following variation (which I'd prefer obviously) will fail to compile:

listAllFiles rootdirpath reldirs modtimer =
    let allfiles = (dirpaths >>~ foreachdir) >~ concat
        ...

Isn't that odd, given how the successful >~~ declared locally right above was defined in exactly the very identical way as the imported >~?

Where's the logic in that, can anyone share their insights on this? Oh, here's the error:

Files.hs:88:21: error:
* Couldn't match type `IO' with `[]'
  Expected type: [[[(FilePath, Data.Time.Clock.UTCTime)]]]
    Actual type: IO [[(FilePath, Data.Time.Clock.UTCTime)]]
* In the first argument of `(>~)', namely
    `(dirpaths >>~ foreachdir)'
  In the expression: (dirpaths >>~ foreachdir) >~ concat
  In an equation for `allfiles':
      allfiles = (dirpaths >>~ foreachdir) >~ concat

.. but obviously this question isn't about how to deal with "Couldn't match type 'a' with 'b'" errors per-se / in the general case --- keep in mind in a functional language I expect identical definitions to work identically, whether defined in a local let or in an imported module. What in the heck could be disrupting this general principle in this specific instance?

It's not a show-stopper, I could skip the fancy ops go fmap concat (etc) and just get on with business. But I guess there's maybe something deeper to learn here (or an obscure bug encountered to be reported)!

metaleap
  • 2,132
  • 2
  • 22
  • 40
  • 2
    No idea, but I'd try adding an explicit type signature for `>~` as well in you module `Util` – chi Jan 01 '17 at 00:43
  • 4
    This sounds like the monomorphism restriction - which @chi's suggestion would address. And that's also why `>>~` needed a type signature. And for what it's worth, only primitive functions are built-in. Certainly nothing in `Control.Monad` is primitive. – Carl Jan 01 '17 at 00:53
  • 1
    *"The explicit type sig is only because despite the bleedingly obvious "it's just an alias for a built-in func" GHC couldn't figure this out and forced me to, so let's ignore this here."* No. Don't ignore. That's exactly the source for your error. Never write pointfree bindings without a type signature if you want to export them. Even better, never export any function without a type signature, their behavior might break (silently) on a library update. – Zeta Jan 01 '17 at 08:04
  • For simple `my_alias_name = defined_elsewhere` no-special-annotations usage, not sure I'll ever grasp why the issue even comes up. In each & every such instance, right after the successful parse and first round of processing, `my_alias_name` shouldn't even *exist* as its own identity anymore and be replaced throughout by the thing it pointed to, no? Why keep such useless pointers even around, they only existed (indeed, given their *id* nature only possibly *could* exist) for readability/swappability.. This then wouldn't even necessitate type inference since the original definition is taken. – metaleap Jan 01 '17 at 09:07
  • @chi tried (just used what *ghci* gave me on `:t (flip fmap)`) and other code that previously compiled (and worked) now demanded type sigs too apparently or in any event type-errored-out. Well I tend to wait with my sigs until a project is "done", so in the very few cases where `>~` won't work (usually in combination with `>>~`) I'll just go with `<$>` instead. – metaleap Jan 01 '17 at 09:28

0 Answers0