在函数中声明函数的类型

oso*_*nyj 3 haskell types function

我有两个功能:

prop_merge_check :: Ord a => [a] -> [a] -> Bool
prop_merge_check xs ys = length (merge xs ys) == length (sort (xs ++ ys))

prop_unzip_check :: Ord a => [(a,b)] -> Bool
prop_unzip_check xs = length (unzip xs) >= 0
Run Code Online (Sandbox Code Playgroud)

如何在函数本身中声明函数的类型?

我尝试过这种方式,但对我来说却没有用。

prop_merge_check xs ys = length (merge (xs::[a]) (ys::[a])) 
                           == length (sort ( (xs::[a]) ++ (ys::[a]) ))

prop_unzip_check xs = length (unzip (xs::[(a,b)])) >= 0
Run Code Online (Sandbox Code Playgroud)

Chr*_*ner 6

这是Haskell隐式forall的副作用。Haskell会根据需要自动将“ forall”添加到所有类型签名,这些签名充当“作用域”规则,将名称限制在特定区域。Haskell将您的签名解释为:

prop_merge_check :: forall a. Ord a => [a] -> [a] -> Bool
prop_merge_check xs ys =
    length (merge (xs::forall a. [a]) (ys:: forall a. [a])) == (length (sort ((xs:: forall a. [a]) ++ (ys:: forall a. [a]))))
Run Code Online (Sandbox Code Playgroud)

那是; 它会将a每个签名中的每个都视为一个完全不同的变量!这就是为什么它不能使类型正常工作。这是一个烦人且不明显的怪癖,但是有一种解决方法。

如果启用ScopedTypeVariables并在类型签名中提供显式的 forall,则告诉Haskell我们希望类型变量的范围跨越整个函数体:

{-# LANGUAGE ScopedTypeVariables #-}
-- ^ Put that at the top of your module

prop_merge_check :: forall a. Ord a => [a] -> [a] -> Bool
prop_merge_check xs ys =
    length (merge (xs::[a]) (ys::[a])) == (length (sort ((xs::[a]) ++ (ys::[a]))))
Run Code Online (Sandbox Code Playgroud)

应该编译该版本,因为现在a所有签名都被认为是相同的。我们可以一次量化多个类型变量:

prop_unzip_check :: forall a b. Ord a => [(a,b)] -> Bool
prop_unzip_check xs = length (unzip (xs::[(a,b)])) >= 0
Run Code Online (Sandbox Code Playgroud)

不幸的是,目前没有一种简单的方法可以在顶级签名中不添加显式的forall来进行这种操作,但是有一些建议可以改变这种行为。他们可能不会很快到来。所以我不会屏住呼吸

祝好运!您可以在ScopedTypeVariables和ExistentialQuantification上查找文档,以了解有关此怪癖的更多信息。