Haskell 是否可以在现有类型的子集上定义函数?
我是Haskell的新手,我想知道是否可以定义一个只在现有类型的子集上定义的函数,而不需要定义新类型 示例:我想创建一个只接受偶数整数(或偶数自然数等)并返回该数平方的函数,如:Haskell 是否可以在现有类型的子集上定义函数?,haskell,Haskell,我是Haskell的新手,我想知道是否可以定义一个只在现有类型的子集上定义的函数,而不需要定义新类型 示例:我想创建一个只接受偶数整数(或偶数自然数等)并返回该数平方的函数,如: squared :: 2*Integer -> Integer squared n = n*n 当然,上述两条线不起作用 我知道我可以这样写: squared' :: Integer -> Integer squared' n | (even n) = n*n | otherwise = err
squared :: 2*Integer -> Integer
squared n = n*n
当然,上述两条线不起作用
我知道我可以这样写:
squared' :: Integer -> Integer
squared' n
| (even n) = n*n
| otherwise = error "n is not even!"
或者类似的东西,但我想知道像非工作示例这样的东西是否也可能
我希望这个问题不是完全愚蠢的(或者已经被回答了),但我真的不太了解Haskell(所以寻找答案也有点困难) 通常不会。这样的东西叫做子集类型,它是Haskell没有的依赖类型的一个标志。通常它是通过将一个值与一个值满足某些属性的证明装箱来实现的,但是由于我们在Haskell中没有证明的概念,所以我们被卡住了 通常,伪造它的方法是使用“智能构造函数” 然后隐藏
偶数
构造函数
如果你真的想要它,你可以切换到一种可以与Haskell进行互操作的语言,这种语言具有依赖类型(请记住Coq和Agda spring)。否。类型系统需要支持细化类型(或完全依赖类型,如@jozefg所建议) 这是一个带有细化类型的Haskell扩展
将子集包装为新类型
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
一种可能是
newtype Even n = Even n
getEven (Even n) = 2*n
squared :: Num n => Even n -> Even n
squared (Even n) = Even (2*n*n)
正如其他地方提到的,LiquidHaskell中的细化类型可以表达这一点。下面是它的样子:
module Evens where
{-@ type Even = {v:Int | v mod 2 = 0} @-}
{-@ square :: Even -> Int @-}
square :: Int -> Int
square n = n * n
-- calling the function:
yup = square 4
-- nope = square 3 -- will not compile if this is uncommented
您可以将其插入此处进行尝试:对于依赖类型,在Haskell Hooray中并不容易!如果依赖类型的概念有点混乱,请查看以下视频:。它提供了一个很好的例子,使用依赖类型来提供额外的信息,如列表的长度等。所有这些都在类型级别。这不起作用,
1::EvenInteger
将1注入偶数域。。。你说得对。如果你愿意处理语法上的丑陋,这个解决方案可以在不派生Num
的情况下工作。不过,在这种情况下,我认为治疗比疾病更糟糕:(
module Evens where
{-@ type Even = {v:Int | v mod 2 = 0} @-}
{-@ square :: Even -> Int @-}
square :: Int -> Int
square n = n * n
-- calling the function:
yup = square 4
-- nope = square 3 -- will not compile if this is uncommented