Правильный способ импорта вещей, уже определенных в прелюдии в Haskell

Я пытаюсь определить складной экземпляр в Haskell и у меня есть некоторые проблемы с импортом.

Итак, первая попытка : класс MyList модуль где

import Data.Foldable

data MyList a = MyList [a]

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

результат (нормальный, но раздражает)

неоднозначное возникновение 'foldr'

Итак, я думаю, что я должен скрыть это от прелюдии : класс MyList модуль где

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

эта компиляция, я загружаю в ghci и пробую некоторые основные вещи:

*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>

так выражения производится работы, но foldl не. Мой первый вопрос

должен ли я скрывать вручную каждый метод, определенный в данных.Складная из прелюдии-это хороший способ сделать это ?

.

чтобы избежать этой проблемы, я попытался выполнить квалифицированный импорт : класс MyList модуль где

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

кажется, компилируется в ghc, но

*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 не найден, но удивительно F. foldr работает в ghci.

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

но только в ghci, если я пытаюсь чтобы импортировать MyList в файл, foldr, F. foldr, MyList.Ф. выражения производится и класса MyList.фолдр не работает.

почему он работает в ghci, но не в реальном ?

думаю, мне нужно импортировать данные.Складная снова (и снова в каждом файле с помощью MyList)

есть ли лучший способ сделать это (например, экспорт данных.Складная в MyList)?

(Я новичок в Haskell и особенно с модулями)


после нескольких ответов, кажется, есть нет чистого решения этой проблемы. Тем не менее, я уверен, что я не первый, кто это делает, так что

какова обычная практика решения такого рода проблем?

Спасибо за помощь.

5 ответов


вот вариант решения Томаса Эдинга, с меньшим набором текста. В принципе, вы можете импортировать (в Prelude') Prelude, скрывая некоторые функции, а затем повторно экспортировать Prelude; это будет экспортировать Prelude минус эти функции. Этот метод обычно полезен для записи модуля интерфейса, повторно экспортирующего только некоторые функции в библиотеке.

вы можете также реэкспорт Data.Foldable.

где я заменил некоторые функции прелюдии эквивалентами (примеры для Foldable и Category).

module Prelude2 (module Prelude, module Data.Foldable, module Control.Category) where

import Prelude hiding (id, (.), foldr)
import Data.Foldable (Foldable, foldr) -- You might want to import everything.
import Control.Category (Category((.), id))
-- Try out replacing with:
-- import Control.Category ()
-- to see that no (.) is available.

использование:

module Foo where
import Prelude()
import Prelude2

а именно, обратите внимание на типы foldr и (.) на Foo, как показано GHCi:

$ ghci Foo.hs
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 2] Compiling Prelude2         ( src-lib/Prelude2.hs, interpreted )
[2 of 2] Compiling Foo              ( /Users/pgiarrusso/AeroFS/Repos/pts-bluevelvet/src-lib/Foo.hs, interpreted )
Ok, modules loaded: Foo, Prelude2.
*Foo> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
*Foo> :t (.)
(.) :: Category cat => cat b c -> cat a b -> cat a c
*Foo>

если вы попробуете предложение заменить

 import Control.Category ()

GHCi покажет вам это (.) не определена в Foo:

*Foo> :r
[1 of 2] Compiling Prelude2         ( src-lib/Prelude2.hs, interpreted )
[2 of 2] Compiling Foo              ( /Users/pgiarrusso/AeroFS/Repos/pts-bluevelvet/src-lib/Foo.hs, interpreted ) [Prelude2 changed]
Ok, modules loaded: Foo, Prelude2.
*Foo> :t (.)

<interactive>:1:1: Not in scope: `.'

почему он работает в ghci, но не в реальном?

потому что в вашем сеансе GHCi вы вводили выражения в контексте MyList модуль, so F.foldr был в области, но если вы импортируете MyList в другой модуль, то только имена, экспортируемые MyList и другие импортированные модули находятся в области видимости.

ваша догадка верна - в каждом модуле с помощью Data.Foldable.foldr вы должны

import qualified Data.Foldable as F

имена, экспортируемые модулем неквалифицированный; квалификация или нет этих имен определяется при импорте модуля.

на протяжении многих лет предлагалось разрешить экспорт квалифицированных имен, но на сегодняшний день ничего не реализовано.


относительно неявного Prelude import, вы можете добавить следующую прагму языка, а затем явно импортировать вещи из Prelude, но это может стать уродливее, чем просто скрывать вещи от Prelude или используя квалифицированный импорт Data.Foldable.

{-# LANGUAGE NoImplicitPrelude #-}

import Prelude (someFunction)

почему это может быть уродливее? Потому что вам может потребоваться импортировать типы данных и функции, которые принимаются как должное, или даже функции, которые явно не используются в коде:

{-# 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]

Я говорил вам о это не потому, что это хорошее решение, а просто знать, что есть такая вещь.


вы могли бы сделать Prelude' модуль, который экспортирует только то, что вы хотите. Затем вы можете начать свой фактический модуль следующим образом:

import Prelude ()
import Prelude'
import Data.Foldable

конечно, вы должны сделать тяжелую работу в Prelude', но, по крайней мере, это многоразовые.

пояснение:

прелюдия'.hs:

module Prelude' (
    id
  , Num (..)
  , everthing you want exported for your 'customized' prelude module goes in this list
  ) where

Я перечитал ваш вопрос и некоторые из ваших комментариев, и я думаю, что ближе всего вы можете получить то, что хотите, что-то вроде этого:

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

по сути, MyList реэкспорт на Data.Foldable module, так что кому-то, использующему ваш модуль, не придется импортировать данные.Снова складывается, но..... ей придется скрыть некоторые функции от 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]

ИМХО, это хорошо. Вы не должны решать, как и то, что кто-то импортирует в свою модули.