我正在尝试通过使用我自己的类型类Max和List实例来实现max迭代器(如在Ruby中(。但是我无法使类型正确。这是否意味着"b"不能与"a"相同?但是我想通过自己的价值获得最大项目是什么?
class Max t where
c_max :: (a->b) -> t a -> a
instance Max [] where
c_max f [a] = a
c_max f (x:xs) = max (f x) (c_max f xs)
main = putStrLn $ show $ c_max (x-> x) [1,2]
我无法使类型正确。这是否意味着
b
不能与a
相同?
它可以,但两者本身并不相同。
但是,在main
函数中使用c_max
不会引起此问题。这里基本上有两个问题。
首先,执行从a
到b
的映射,但未将b
限制为作为Ord
实例的类型。因此,我们无法比较两个b
来确定哪个b
最大。因此,我们应该添加一个Ord b
类型约束:
class Max t where
c_max ::Ord b =>(a -> b) -> t a -> a
在instance Max []
中,max
比较两个b
,并返回最大的b
。但是给定您的类型签名,您希望返回相应的a
。我们可以通过以下方式实现这一点:
instance Max [] where
c_max f [a] = a
c_max f (x:xs) |f x > f mx= x
| otherwise = mx
where mx = c_max f xs
例如:
Prelude> putStrLn $ show $ c_max (x-> x) [1,2]
2
以上不是最有效的实现,因为我们在这里将为每个项目多次计算f x
。我将其作为进一步优化的练习。
请注意,在Haskell中,有一个maximum :: (Foldable f, Ord a) => f a -> a
函数适用于Foldable
s。因此,这将适用于列表、Tree
等。人们可以通过稍微改变"折叠函数"来定义一个maximumBy
或类似的东西,也可以在Foldable
上运行。