Я пытаюсь определить Складной экземпляр в 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>
Так foldr работы, но 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. F.foldr и MyList.foldr не работают.
Я предполагаю, что должен импортировать Данные. Складной снова (и снова в каждом использовании файлов MyList)
(Я - новичок в Haskell и особенно с модулями),
После наличия нескольких ответов кажется, что нет никакого чистого решения этой проблемы. Однако я вполне уверен, я не первое выполнение это, таким образом,
Спасибо за Вас справка.
Вы можете сделать модуль Prelude'
, который экспортирует только то, что вам нужно. Затем вы могли бы начать свой настоящий модуль следующим образом:
import Prelude ()
import Prelude'
import Data.Foldable
Конечно, вам придется выполнять работу в Prelude'
, но, по крайней мере, он будет многоразовым.
Уточнение:
Prelude'.hs:
module Prelude' (
id
, Num (..)
, everthing you want exported for your 'customized' prelude module goes in this list
) where
Я перечитал ваш вопрос и некоторые из ваших комментариев, и я думаю, что самое близкое вы можете понять, что вы want выглядит примерно так:
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
, так что кому-то, использующему ваш модуль, не придется импортировать данные. Снова складывается, но ... ей придется скрыть некоторые функции из 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]
ИМХО, это хорошо. Не стоит решать, как и что кто-то импортирует в свои собственные модули.
Что касается неявного импорта Prelude
, вы можете добавить следующую языковую прагму, а затем явно импортировать вещи из 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]
Я сказал вам об этом не потому, что это хорошее решение, а просто чтобы знать, что есть такая вещь.
Почему это работает в ghci, но не работает на самом деле?
Поскольку в сеансе GHCi вы вводили выражения в контексте модуля MyList
, поэтому F.foldr
находился в области действия, но если вы импортируете MyList
в другой модуль, тогда только имена, экспортированные из MyList
, и другие модули, которые вы импортировали, попадают в область видимости.
Ваше предположение верно - в каждом модуле, использующем Data.Foldable.foldr
, вы должны
import qualified Data.Foldable as F
Имена, экспортируемые модулем, неквалифицированы; квалификация этих имен решается при импорте модуля.
На протяжении многих лет выдвигались предложения разрешить экспорт полных имен, но на сегодняшний день ничего не реализовано.