我有一个名为
Types.hs
的 Haskell 文件,其中包含以下定义:
module Types
( KnapsackItem
) where
data KnapsackItem = KnapsackItem {
weight :: Int,
cost :: Int
} deriving (Show, Eq)
然后是我的
Main.hs
(为简单起见,这里也缩短了):
import Types
evalTotal :: [KnapsackItem] -> [KnapsackItem] -> (Int, Int, String)
evalTotal items sub = (sum $ map weight sub, sum $ map cost sub, outputString)
where outputString = "[" ++ unwords [if item `elem` sub then "1" else "0" | item
<- items] ++ "]"
main :: IO ()
main = do
let items = [KnapsackItem {...}, KnapsackItem{...}, ...] -- details omitted in this example
print $ map (evalTotal items) (subsequences items)
我收到以下错误:
src/Main.hs:67:34: Not in scope: `weight'
src/Main.hs:67:56:
Not in scope: `cost'
Perhaps you meant one of these:
`const' (imported from Prelude), `cos' (imported from Prelude),
`cosh' (imported from Prelude)
如您所见,它不会让我访问每个
KnapsackItem
的属性。但是,如果我将数据定义移至 Main.hs
并避免导入,它就会起作用。请问我做错了什么?
将
Types.hs
开头的导出列表修改为:
module Types
( KnapsackItem (..)
) where
这将使模块导出
KnapsackItem
的所有构造函数和字段。没有(..)
,只导出类型的名称。
有关
(..)
和相关事项的一些额外评论,另请参阅括号中的双点在 Haskell 中是什么意思?
简单地在导出列表中命名一个类型只会导出type。如果您希望类型对下游模块是抽象的,这就是您需要的,保持细节隐藏和不可访问(通常只有当您还导出其他函数以使用该类型时)。
如果您还想导出数据构造函数和/或字段,则需要明确说明。在你的情况下,它看起来像这样:
module Types
( KnapsackItem ( KnapsackItem, weight, cost )
) where
仔细注意,类型级别的
KnapsackItem
和值级别的KnapsackItem
是两个不同的项(尽管对于具有单个数据构造函数的类型给它们相同的名称是非常传统的),所以是否每个都被导出单独控制。
因为导出所有类型的构造函数和字段或不导出它们是很常见的,所以有一个快捷语法可用于导出所有内容。无需在类型名称后单独列出每个构造函数和字段,您只需使用
(..)
将它们全部导出:
module Types
( KnapsackItem (..)
) where
相同的语法也适用于导入列表;
import Types ( KnapsackItem )
只导入类型,需要一个子列表(可以是(..)
)来导入字段和数据构造函数。但是您已经使用了从模块导入everything 的形式,所以这不是这里的问题(但如果您在实际代码中使用显式导入列表,则可能是)。