tags:

views:

141

answers:

4

I'm trying to define a Foldable instance in Haskell and I have some problem with import.

So first try : module MyList where

import Data.Foldable

data MyList a = MyList [a]

instance Foldable (MyList) where
  foldr f b (MyList as) = foldr f b as

Result (normal but annoying)

Ambiguous occurrence `foldr'

So, I guess I have to hide it from the Prelude : module MyList where

import Prelude hiding (foldr)
import Data.Foldable

data MyList a = MyList [a]

instance Foldable (MyList) where
  foldr f b (MyList as) = foldr f b as

This compile, I load into ghci and try some basic stuff :

*MyList> foldr (:) "" (MyList "hello")
"hello"
*MyList> foldl (flip (:)) "" (MyList "hello")

<interactive>:1:0:
    Ambiguous occurrence `foldl'
    It could refer to either `Prelude.foldl', imported from Prelude at MyList.hs:4:0-28
                          or `Data.Foldable.foldl', imported from Data.Foldable at MyList.hs:5:0-19
*MyList>

So foldr works, but foldl doesn't. My first question is

Do I have to hide manually every single method defined in Data.Foldable from the Prelude is their a nice way to do it ?

.

To avoid this problem , I tried to do an qualified import : module MyList where

import qualified  Data.Foldable as F

data MyList a = MyList [a]

instance F.Foldable (MyList) where
  foldr f b (MyList as) = foldr f b as

Seems to compile in ghc but

*MyList> foldr (:) "" (MyList "hello")

<interactive>:1:14:
    Couldn't match expected type `[Char]'
           against inferred type `MyList Char'
    In the third argument of `foldr', namely `(MyList "hello")'
    In the expression: foldr (:) "" (MyList "hello")
    In the definition of `it': it = foldr (:) "" (MyList "hello")

foldr is not found but suprisingly F.foldr works in ghci.

*MyList> F.foldr (:) "" (MyList "hello")
"hello"

But in ghci only, if I'm trying to import MyList in file, foldr, F.foldr, MyList.F.foldr and MyList.foldr doesn't work.

Why does it work in ghci but not in real ?

I guess I have to import Data.Foldable again (and again in every files using MyList)

Is there a better way to do it (like exporting Data.Foldable in MyList) ?

(I'm a newbie in Haskell and especially with modules)


After having a couple of responses, it seems there is no clean solution to this problem. However, I'm pretty sure I'm not the first doing that, so

What is the common practice to deal with that kind of problem?

Thanks for you help.

+1  A: 

You could make a Prelude' module that exports only the stuff you want. Then you could begin your actual module as follows:

import Prelude ()
import Prelude'
import Data.Foldable

Granted you have to do the grunt work in Prelude', but at least it is reusable.

Clarification:

Prelude'.hs:

module Prelude' (
    id
  , Num (..)
  , everthing you want exported for your 'customized' prelude module goes in this list
  ) where
trinithis
Ok, do you mean something like Prelude'=Prelude-Data.Foldable ? Supposing now, I want to import Data.List for example should I define a Prelude''=Prelude-Data.Foldable-Data.List. Not sure that's really reusable ...
mb14
The problem is, I don't want to export anything in particula from the prelude, I just would like a Prelude without what it's in Foldable.I would like to avoid having to explicitly export stuff.
mb14
+7  A: 

Why does it work in ghci but not in real?

Because in your GHCi session you were typing expressions in the context of the MyList module, so F.foldr was in scope, but if you import MyList into another module then only the names exported by MyList, and the other modules you imported, are in scope.

Your guess is correct - in every module using Data.Foldable.foldr, you have to

import qualified Data.Foldable as F

The names exported by a module are unqualified; the qualification or not of those names is decided when the module is imported.

There have been proposals over the years to allow exporting qualified names, but to date nothing has been implemented.

Simon Marlow
+4  A: 

Regarding the implicit Prelude import, you could add the following language pragma, and then explicitly import things from Prelude, but it might get uglier than simply hiding things from the Prelude or using an qualified import of Data.Foldable.

{-# LANGUAGE NoImplicitPrelude #-}

import Prelude (someFunction)

Why it might get uglier? Because you might have to import data types and functions that are taken for granted, or even functions that aren't explicitly used in the code:

{-# LANGUAGE NoImplicitPrelude #-}
module Main (main) where

-- we import fromInteger although it's not explicitly used
import Prelude (Int, foldl, fromInteger, (+), putStrLn, (.), ($), IO, show)

sum :: [Int] -> Int
sum = foldl (+) 0

main :: IO ()
main = putStrLn . show $ sum [1,2,3]

I told you about this not because it's a good solution, but just to know that there's such a thing.

Ionuț G. Stan
That's what I want to avoid indeed ;)
mb14
Do you need NoImplicitPrelude if you manually cherry pick some Prelude functions?
trinithis
@trinithis, no, but the problem of importing the most basic of the data types and functions remains. Hiding or qualified imports seem to be the best solution.
Ionuț G. Stan
+1  A: 

I've re-read your question and some of your comments and I guess the closest you can get to what you want is something like this:

module MyList
  (
    module Data.Foldable,
    MyList(..)
  )
where


import Data.Foldable
import Prelude (($))


data MyList a = MyList [a]

instance Foldable (MyList) where
    foldr f b (MyList as) = foldr f b as

Basically, MyList re-exports the Data.Foldable module, so that someone using your module won't have to import Data.Foldable again, but... she will have to hide some functions from the Prelude.

module Main (main) where


import Prelude hiding (foldr)
import MyList


mySum :: MyList Int -> Int
mySum = foldr (+) 0

main :: IO ()
main = putStrLn . show . mySum $ MyList [1,2,3]

IMHO, this is a good thing. You should not decide how and what someone imports in his own modules.

Ionuț G. Stan
Y agree with the "You should not decide what should imports". I guess the problem come from the fact that List are not Foldable by default. So I my mind, when I m instanciating Foldable I expect MyList to be usable with foldr (the Prelude one), but it's not :(Which mean foldr and Foldable.foldr are not the same function. I think I should go for the qualified import
mb14