如何为这两个具有相同定义的函数提供更通用的类型?

时间:2017-02-25 14:15:06

标签: haskell types

是否有可能以某种方式使下面的代码片段更通用,我们基本上有2个函数具有相同的代码,唯一的区别是函数定义,是否有可能以某种方式抽象出来

unsafeListHandling :: [a] -> ([a] -> a) -> Maybe a
unsafeListHandling xs fx = if null xs then Nothing else Just $ fx xs

unsafeListHandling2 :: [a] -> ([a] -> [a]) -> Maybe [a]
unsafeListHandling2 xs fx = if null xs then Nothing else Just $ fx xs

1 个答案:

答案 0 :(得分:3)

this one等答案涵盖了系统的方法。但在许多情况下,仔细查看我们对类型签名的了解是我们需要弄清楚的。

unsafeListHandling  :: [a] -> ([a] ->  a ) -> Maybe  a
unsafeListHandling2 :: [a] -> ([a] -> [a]) -> Maybe [a]

我们对广义unsafeListHandling知道的事情:

  • 它的第一个参数应该是一个任意类型的列表(让我们把它作为你强加的要求)。
  • 它应该将该类型的列表上的函数作为其第二个参数。
  • 它应该产生与第二个参数的结果类型匹配的Maybe
  • 应该可以将第二个参数的结果类型专门化为第一个参数的(列表)类型或其对应的元素类型(覆盖两个签名之间的差异)。

如果我们将其作为类型签名写下来,我们得到:

unsafeListHandling :: [a] -> ([a] -> b) -> Maybe b

a是任意的bb ~ [a]b ~ a都是有效的专精。如果我们将b视为一个自由且不受约束的类型变量,我们可以看到没有什么能阻止我们将它专门化为[a]a;如此,一般类型签名确实是:

unsafeListHandling :: [a] -> ([a] -> b) -> Maybe b
unsafeListHandling xs fx = if null xs then Nothing else Just $ fx xs

如果我们遵循melpomene的建议,并在不添加任何签名的情况下向GHCi询问您的功能类型......

GHCi> :t \xs fx -> if null xs then Nothing else Just $ fx xs
\xs fx -> if null xs then Nothing else Just $ fx xs
  :: Foldable t => t a -> (t a -> a1) -> Maybe a1

...除了[a]Foldable t => t a的无关紧要的概括之外,我们得到了这一点,因为null的类型是Foldable t => t a -> Bool。顺便说一句,如果您使用的是GHC 8,则可以启用TypeApplications扩展程序,并将其用作为您的类型俄罗斯方块专门化null的便捷方式:

GHCi> :set -XTypeApplications
GHCi> :t \xs fx -> if null @[] xs then Nothing else Just $ fx xs
\xs fx -> if null @[] xs then Nothing else Just $ fx xs
  :: [a] -> ([a] -> a1) -> Maybe a1

总结一下,广义函数实际上做了你想做的事情的演示:

GHCi> (\xs fx -> if null @[] xs then Nothing else Just $ fx xs) [1..7] head
Just 1
GHCi> (\xs fx -> if null @[] xs then Nothing else Just $ fx xs) [1..7] tail
Just [2,3,4,5,6,7]