在Haskell中使用类型别名的正确方式是什么?

8

我是一个Haskell的入门者。在尝试完成hackerrank上的一些练习时,我遇到了一个错误,这让我想知道是否有“正确”的方法来解决它。

我尝试做的是这个:

import Data.Matrix

newtype Puzzle = Matrix Char

complete :: Puzzle -> Bool
complete p = '-' `elem` (toList p)

[... more functions on 'Matrix Char']

这给了我:

Couldn't match expected typeMatrix Charwith actual typePuzzleIn the first argument of ‘toList’, namely ‘p’
    In the second argument of ‘elem’, namely ‘(toList p)’

显而易见的解决方案当然是使用Matrix Char而不是Puzzle。但我觉得这不是一个优雅的解决方案。更具体类型的抽象感觉是正确的方法...
2个回答

11

使用 type 而不是 newtype。前者创建一个类型别名,后者是一个新的类型声明。特别地,newtypedata 的一种特殊情况,其中新类型代表现有类型的 "包装器"(这是编译器可以优化的一种情况)。


1
就这样了!谢谢。我将在约7分钟内接受答案。 - Chirs

7

我认为比Jeffrey的回答提供的更好的解决方案,至少对于比玩具游戏更庞大的代码库而言,是继续使用newtype,但将代码改为以下形式:

import Data.Matrix

newtype Puzzle = Puzzle (Matrix Char)

complete :: Puzzle -> Bool
complete (Puzzle matrix) = '-' `elem` toList matrix

这将允许您继续使用真正独特的数据类型,而不是采用类型别名,后者不会引入任何新类型,并且将允许完全可互换地使用 PuzzleMatrix Char,没有增加类型安全性(也没有表现力)。
此外,Jeffrey 是正确的,newtype 更类似于 data 而不是 type——newtype 提供了一些性能优化,但更受限制,并且稍微影响了程序评估语义。最好阅读有关在 Haskell 中定义类型和类型别名的各种方式的所有信息。
在您的情况下,您可能会将 data 替换为 newtype 而不改变程序的行为;其余部分应该继续以相同的方式工作。
另请参见:Haskell type vs. newtype with respect to type safety

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接