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



我完全是Haskell的初学者。在试图解决hackerrank上的一些练习练习时,我偶然发现了一个错误,这让我怀疑"正确的方法"(tm)。

我想做的是:

import Data.Matrix
newtype Puzzle = Matrix Char
complete :: Puzzle -> Bool
complete p = '-' `elem` (toList p)
[... more functions on 'Matrix Char']

,这给了我:

Couldn't match expected type ‘Matrix Char’
                with actual type ‘Puzzle’
    In the first argument of ‘toList’, namely ‘p’
    In the second argument of ‘elem’, namely ‘(toList p)’

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

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

我认为比Jeffrey的回答更好的解决方案,至少在比玩具游戏更实质性的代码库的情况下,是继续使用newtype,但将代码更改为:

import Data.Matrix
newtype Puzzle = Puzzle (Matrix Char)
complete :: Puzzle -> Bool
complete (Puzzle matrix) = '-' `elem` toList matrix

这将允许您继续使用真正不同的数据类型,而不是诉诸类型别名,后者不会引入任何新类型,并且允许PuzzleMatrix Char完全可互换使用,而不增加类型安全性(也没有表达性)。

此外,Jeffrey是对的,newtypetype更类似于data——newtypedata提供了一些性能优化,但更受限制,稍微影响程序评估语义。您最好仔细阅读Haskell中定义类型和类型别名的所有方法。

在你的情况下,你可以用data代替newtype而不改变程序的行为;程序的其余部分应该继续相同地工作。

参见:关于类型安全的Haskell类型与newtype

相关内容

最新更新