【问题标题】:Haskell Type SignaturesHaskell 类型签名
【发布时间】:2017-12-05 18:38:00
【问题描述】:

我是 haskell 的新手,我读过一些关于这个叫做类型签名的东西,但是有一些东西我不明白。

这是我正在查看的代码:

--mult applies product
mult :: Num a => [a] -> a
mult  = foldr (*) 1 

--posList filters positive numbers out
posList :: (Ord a, Num a) => [a] -> [a]
posList = filter (>0) 

--trueList determines whether all of the members of a list are T or not
trueList :: [Bool] -> Bool
trueList  =  foldr(&&) True 

--evenList determines where all of the members of a list are even or not
evenList :: (Integral a, Foldable t) => t a -> Bool
evenList x = if (((foldr (+) 2 x ) `mod` 2) == 0) then True else False

所以,我知道你可以用不同的方式更轻松地完成这些功能,但我被分配使用更高阶的功能 mapfilterfoldr,所以我不得不这样做。无论如何,我了解这些功能是如何工作的,因为我是编写它们的人,我不明白这些术语IntegralFoldable,它们是什么意思?以及它们在 Haskell 中的名称是什么?

【问题讨论】:

  • 你测试evenList了吗?我建议你试试evenList [1,3]
  • Integral 和 Foldable 是 type classes,google 这个词。基本上Foldable t 的意思是“t 是一个类似列表的类型”。
  • 类型类是 Haskell 中的重载方式。一个类型通过实现一些函数来实现一个类型类。例如,(+) 的类型是Num a => a -> a -> a,所以如果我定义了一个我希望能够添加的类型Foo,那么我需要定义(+) :: Foo -> Foo -> Foo,我只能通过实例化Num 类来实现Foo
  • @chi ahahahha 感谢提醒我修复了 evenList :: [Int] -> Bool evenList xs = foldr (&&) (True) (map (even) xs)
  • @MostafaIbrahim 好多了 ;-)

标签: haskell types


【解决方案1】:

这些是对多态类型的约束

Haskell 尽管是静态类型的,但通过一个名为parametric polymorphism 的系统,可以很容易地编写可以处理不同类型的函数。我将首先为您的所有函数提供具体(单态)签名:

mult :: [Integer] -> Integer
mult  = foldl' (*) 1  -- foldl' is better for performance/memory than foldr

posList :: [Integer] -> [Integer]
posList = filter (>0) 

trueList :: [Bool] -> Bool
trueList  =  foldl' (&&) True

evenList :: [Integer] -> Bool
evenList x = foldl' (+) 2 x `mod` 2 == 0
            -- `if True then True else False` is tautological

所有这些签名都有效(无论是改进的实现还是您原来的实现)。

但它们适用于Integer 的列表。这并不总是足够普遍。例如,计算小数列表的乘积是完全合理的。但是对于单态签名,mult [1.5, 2.4, 20] 不起作用:这些数字与Integer 不兼容。您不想将函数限制为整数,您只希望它使用任何数字类型并始终获得与元素相同类型的结果。即,您基本上想要签名

mult :: ∀ a . [a] -> a

...阅读“对于所有类型a,函数mult 获取一个列表,其元素类型为a,并给出一个a-value 作为结果。当你有这样的类型变量时,它在 Haskell 中是隐含的,即你也可以这样做

mult :: [a] -> a

但这还不行,因为函数必须能够乘以元素。但这对于 all 类型是不可能的,仅适用于 number types。因此,您添加了约束

mult :: Num a => [a] -> a

对于posList,这几乎是一样的:签名本质上是

posList :: [a] -> [a]

但您还需要能够将 (Ord) 元素与 0 (Num) 进行比较。因此约束

posList :: (Num a, Ord a) => [a] -> [a]

对于evenList,数值运算为(+)(==)mod。所以原则上我们需要NumEqIntegral,但IntegralNumEq 作为超类,所以仅此而已:

evenList :: Integral a => [a] -> Bool

...不过,这还不是最通用的形式。您可以通过折叠来减少该列表,但列表并不是唯一可以折叠的东西,例如,您还可以折叠数组、映射和Maybe 值。所有可以折叠的容器的类型类都被调用了,你不会猜到的,Foldable。所以我们最终得到了

evenList :: (Integral a, Foldable t) => t a -> Bool

您可以对multtrueList 应用相同的概括:

mult :: (Num a, Foldable t) => t a -> a
trueList :: Foldable t => t Bool -> Bool

【讨论】:

    猜你喜欢
    • 2015-07-22
    • 2016-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多