ghc如何知道使用fmap等定义?

时间:2013-08-13 16:39:51

标签: haskell types

我知道fmap的类型为(a -> b) -> f a -> f b,其中f是一个仿函数(根据仿函数的不同而做不同的事情)。我的基本问题是:给定一些调用fmap r x,ghc如何确定函数f是什么,只是给出了xr的类型?

让我更准确地说明这一点。假设ff'是仿函数,f a = f' a用于某种类型a,但f bf' b不同。如果r的类型为a -> bx的类型为f a,则fmap r x似乎有两种不同的可能结果:类型f bf' b类型的东西。这种含糊不清是如何解决的?

第二个问题:我想通过制作一个奇怪的仿函数来测试这个问题 - 对于任何类型a,可能需要[Int]a,并且对函数执行愚蠢的操作。 ..但我显然没有找到合适的语法,允许我以这种方式指定仿函数。 (有data Newtype a = [Int]这样的东西有效吗?看来我需要创建一个类型类名称才能使它成为仿函数的一个实例。)

编辑:我现在得到了,但是为了记录,真正的问题(这只是我的问题中隐含的)是我没有意识到你不能有一个仿函数Foo这样Foo a 1}}是类似Int的类型,已经存在。

4 个答案:

答案 0 :(得分:2)

我认为您正在寻找的一般答案是Haskell类型使用“种类”进行组织,类似于类型。

这是Functor

class Functor f where
    fmap :: (a -> b) -> f a -> f b

它并不明确,但这意味着f是一个类型* -> *的类型构造函数。只有类型的类型可以Functor s。

这实际上是一个相当强烈的声明。这意味着任何Functor必须在类型参数中具有参数。现在考虑你的陈述:

  

假设f和f'是仿函数,对于某些类型a,f a = f'a,   但是f b和f'b是不同的。

鉴于系统类型,这是不可能的。由于Functor在其类型参数中具有参数,因此f a = f' a隐含f = f',因此f b = f' b

我不完全确定你对“奇怪的仿函数”要求的是什么,但它听起来像Functor类型类无法表达的东西。 IIRC Functor只能在Hask上表达endofunctors;你可能需要一个不同的抽象,允许类别之间的仿函数。

答案 1 :(得分:1)

Haskell类型类基于一阶逻辑分辨率。类型变量上的类型类约束是谓词(如果您曾尝试在该逻辑系统中使用需要类型名称的类型类名称,则可能会看到错误消息,指示此情况)。

Haskell在整个程序中需要为每个(谓词,类型)对提供唯一的解决方案,因此您将无法在Int上创建两个不同的Functor实例。围绕这个的标准方法,例如在Monoid类中可以提供求和或产品的Monoid类,取决于你如何定义你想要使用的monoidal运算符,就是在具体类型上提供newtype包装器你希望这个类有不同的实例。

因此,对于Monoid,我们有newtype Sum a = Sum { getSum :: a }instance Num a => Monoid (Sum a)用于总和monoid,newtype Product a = Product { getProduct :: a }instance Num a => Monoid (Product a)用于产品monoid。

请注意,由于type仅为类型创建别名,因此仅为类型提供多个类实例是不够的。 newtype声明就像type一样,它不会为新类型生成任何额外的运行时结构,但它与type不同,因为它创建了一个新类型而不是{{1}}而不是类型别名。

答案 2 :(得分:0)

这取决于你传递的参数。例如,列表是仿函数,Maybe

也是如此
main = do
   putStrLn $ show (double [1..5])
   putStrLn $ show (double (Just 3))
   putStrLn $ show (double Nothing)

double :: (Functor f, Num a) => f a -> f a
double = fmap (*2)

*Main> main
[2,4,6,8,10]
Just 6
Nothing

double函数适用于持有Num的任何仿函数。

答案 3 :(得分:0)

“假设ff'是仿函数,f a = f' a适用于某种类型a,但f b和{{1}是不同的。“

这没有多大意义。 f' bf相同,或者不相同。你似乎建议某种中间状态,它根据参数类型而变化;这不可能发生。

“如果f'的类型为ra -> b的类型为x,则f a似乎有两种不同的可能结果:某种类型{ {1}}以及fmap r x类型的内容。这种歧义如何解决?“

f b来自哪里?上述签名中没有任何内容提及它。由于f' b的类型为f',因此x的结果必须包含以f a开头的某种类型 - 在本例中为fmap,因为{{1} }}。这完全是明确的。 f的结果总是与您开始使用的是同一个仿函数。