我是Haskell的新手,想知道是否可以定义一个仅在已有类型的子集上定义的函数,而不必实际定义新类型。
示例:我想创建一个只接受整数(甚至是自然数字等)并返回的函数,例如:这个数字平方,如:
squared :: 2*Integer -> Integer
squared n = n*n
当然,以上两行不起作用。
我知道我可以这样写:
squared' :: Integer -> Integer
squared' n
| (even n) = n*n
| otherwise = error "n is not even!"
或类似的东西,但我想知道是否有可能像非工作示例这样的东西。
我希望这个问题不是完全愚蠢的(或者已经回答过了)但是我真的不知道很多Haskell(所以寻找答案也很难)...
答案 0 :(得分:12)
一般没有。这样的事情被称为子集类型,它是Haskell没有的依赖类型的标志。通常它是通过使用证明该值满足某些属性的值来实现的,但由于我们在Haskell中没有证据概念,因此我们陷入困境。
通常伪造它的方法是使用“智能构造函数”。
newtype Even = Even {unEven :: Integer} deriving (Eq, Show, Ord)
toEven :: Integer -> Maybe Even
toEven a | even a = Just $ Even a
| otherwise = Nothing
然后隐藏Even
构造函数。
如果你真的想要它,你可以切换到一种语言,它可以与具有依赖类型的Haskell互操作(考虑到Coq和Agda)。
答案 1 :(得分:6)
没有。类型系统需要支持细化类型(或完全依赖类型,如@jozefg所示)。
这是一个带有细化类型的Haskell扩展。
http://goto.ucsd.edu/~rjhala/liquid/haskell/blog/blog/2013/01/01/refinement-types-101.lhs/
答案 2 :(得分:1)
将子集包装在newtype中
newtype EvenInteger = EvenInteger {
unEvenInteger :: Integer
} deriving (Show, Eq, Ord, Num)
mkEvenInteger :: Integer -> Maybe EvenInteger
mkEvenInteger n = case n % 2 of
0 -> Just $ EvenInteger n
_ -> Nothing
squared :: EvenInteger -> EvenInteger
squared n = n * n
答案 3 :(得分:1)
一种可能性是
newtype Even n = Even n
getEven (Even n) = 2*n
squared :: Num n => Even n -> Even n
squared (Even n) = Even (2*n*n)
答案 4 :(得分:1)
如其他地方所述,LiquidHaskell中的细化类型可以表达这一点。这是它的样子:
<elem><![CDATA[ something ]]></elem>
<elem>something</elem>
您可以通过在此处插入来试试这个:http://goto.ucsd.edu:8090/index.html