Haskell newtype定义

时间:2015-02-09 16:09:04

标签: haskell newtype

我在为家庭作业提供的代码中读到了这句话: -

newtype STR a = STR (Store -> (Result a, Store))

上面的链接看起来像是:

a === (Store -> (Result a, Store))

这怎么可能是一个有效的陈述?这是否意味着a是一个以Store为参数并返回('the same function wrapped in Result', Store)

的函数

2 个答案:

答案 0 :(得分:9)

newtype定义有点令人困惑,因为符号STR有两种不同的含义:即名称类型(第一次出现)和构造函数(第二次出现)。将两者重命名为不同的东西会导致等效的

newtype STRType a = STRConstructor (Store -> (Result a, Store))

换句话说,这会引入一种STRType a类型,其结构与Store -> (Result a, Store)相同(但需要包含在STRConstructor中)

我希望您的课程/书籍已经涉及typedatanewtype之间的差异;否则这将保持相当神秘,我害怕......

答案 1 :(得分:3)

因此,对于数据/新类型定义,左侧包含类型定义,包括名称和某些类型变量,而右侧包含构造函数列表通常还包括名称和类型。一个例子是:

data List x = Nil | Cons x (List x)

请注意,NilCons是您的构造函数,xList xCons构造函数的参数类型,而List是类型的名称(具有种类* -> *;它需要一个类型参数___到"在它可以描述___ s的列表之前将其填入"。

有时我们想要为一个类型添加别名。有两种方法可以做到这一点。首先,type,使类型保持相称 - 所以如果你写type DirectoryPath = [String],那么当你有DirectoryPath时,你可以像字符串列表一样操纵它;特别是您可以使用:++附加到其中;所以"apps" : base_directory完全合法的Haskell。

有时候,你只是想用一个大警告标志来破坏这些功能,如果你不知道自己在做什么,就不要使用它。"为此,您可以帮助编写data FilePath = FilePath [String]。请注意,我们正在滥用符号,将类型命名为与该类型的唯一构造函数相同。现在做同样的事情,你必须写:

case base_directory of FilePath bd -> FilePath $ "apps" : bd

你为什么要这样做?好吧,首先,在上面的语法中,目录结构从右到左增长,而大多数人从左到右编写目录。其次,您可能希望将.添加为无操作(即bd ++ [])和..作为父指针(即tail bd)。您可能还有一些奇怪的约定(例如,如果列表以&#34开始;"那么它是一个绝对目录,否则它是相对于当前目录的)需要维护。最后,您可能希望稍后将代码转换为Maybe [String],以便Nothing值可以表示执行疯狂操作的路径,例如/../..(绝对路径两个父项位于根上方)。

如果你能说:

,这一切都变得容易了
FilePath xs ./ x
    | x == "."  = FilePath xs
    | x == ".." = FilePath (tail xs)
    | otherwise = ...

然后强制执行其他人写的base_directory ./ "apps"

另一个例子是newtype SanitizedString = Sanitized String。由于我们没有使用type,我们得到一个编译时标签,它跟踪我们的代码,确保用户提供的字符串被正确转义,比如说,它们进入数据库插入语句或用户界面或任何地方

您在此处可能使用的是,您可以为该类型编写Monad个实例,从而将其与do - 符号一起使用。

如果您的代码仅包装一个现有类型,newtype避免引入额外的懒惰担忧和数据构造函数延迟等等。否则就像data一样。所以在你的代码中:

newtype STR a = STR (Store -> (Result a, Store))

这不是type同义词,而更像是data构造函数,它最终会在编译后消失。 STR aStore -> (Result a, Store)的别名,它包含在STR构造函数中(因此无法在没有解构赋值的情况下直接用作函数)。