是否可以对公共数据类型实施约束?

时间:2014-05-27 15:26:56

标签: haskell

我有以下代码:

-- A CharBox is a rectangular matrix of characters
data CharBox = CharBox [String]
    deriving Show

-- Build a CharBox, ensuring the contents are rectangular
mkCharBox :: [String] -> CharBox
mkCharBox [] = CharBox []
mkCharBox xxs@(x:xs) =  if (all (\s -> (length s) == length x) xs)
                        then CharBox xxs
                        else error "CharBox must be a rectangle."

[[Char]]必须是矩形的(即所有子列表必须具有相同的长度)才能使模块中的许多功能正常工作。在模块内部,我总是使用mkCharBox“构造函数”,所以我不必一直强制执行此约束。

最初我希望我的模块声明看起来像这样:

module CharBox (
    CharBox, -- No (CharBox) because it doesn't enforce rectangularity
    mkCharBox
) where

但是这样,我模块的用户无法在CharBox上进行模式匹配。在另一个模块中我做了

findWiresRight :: CharBox -> [Int]
findWiresRight (CharBox xs) = elemIndices '-' (map last xs) 

并且ghci抱怨:Not in scope: data constructor 'CharBox'

是否可以强制执行CharBox仅包含矩形数组的约束,同时仍然允许模式匹配?(如果不可能,我也有兴趣知道技术原因。我发现在探索这样的限制时,Haskell通常需要学习很多东西)

2 个答案:

答案 0 :(得分:7)

在vanilla Haskell中,隐藏构造函数并支持模式匹配是不可能的。

解决这个问题的常用方法是:

或:

  • 通过size types将不变量移入类型系统。

答案 1 :(得分:2)

最简单的解决方案是向模块添加提取功能:

extract :: CharBox -> [String]
extract (CharBox xs) = xs

然后使用它而不是模式匹配:

findWiresRight :: CharBox -> [Int]
findWiresRight c = elemIndices '-' $ map last $ extract c