如何从整体或阅读工作

时间:2016-07-19 15:41:42

标签: haskell polymorphism

fromIntegral会返回Num数据类型。但似乎Num能够强制执行DoubleInteger而没有任何问题。类似地,read函数能够返回适合其类型签名所需的任何内容。这是怎么回事?如果我确实需要制作类似的功能,我该怎么做?

3 个答案:

答案 0 :(得分:6)

类型检查器不仅可以推断函数参数的类型,还可以推断返回类型。实际上那里没有特殊情况。如果您将fromIntegralread的结果存储在Integer中,则会调用此类型的版本。您可以用同样的方式创建自己的功能。

例如:

class Foo a where
  foo :: a

instance Foo Integer where
  foo = 7

instance Foo String where
  foo = "Hello"

x :: Integer
x = 3

main = do
  putStrLn foo
  print (foo + x)

由于putStrLn的类型为String -> IO (),因此类型检查器会发现fooputStrLn foo的类型必须为String才能编译程序。 foo的类型为Foo a => a。因此,它推导出a == String并搜索Foo String实例。存在这样的实例,它会导致在那里选择foo :: Foo String => String值。

类似的推理发生在print (foo + x)x已知Integer,因为(+)的类型为Num a => a -> a -> a,类型检查器会推断加法运算符的左参数也必须为Integer所以它会搜索Foo Integer个实例并替换Integer变体。

在C ++中没有从函数参数到(可能)返回类型的指示。类型检查器甚至可以基于对函数预期返回的知识来推断函数参数。另一个例子:

twice :: a -> [a]
twice a = [a,a]

y :: [Integer]
y = twice foo

此处的函数参数类型为Foo a => a,这不足以决定使用哪个foo。但由于结果已知为[Integer],因此类型检查器发现它必须向Integer提供twice类型的值,并通过使用{{1}的相应实例来实现}。

答案 1 :(得分:2)

readtypeclass的成员,这意味着它的实现可能取决于类型参数。

此外,142等数字文字是函数调用fromInteger 1fromInteger 42等的合成糖,以及fromInteger本身是Num类型类的成员。

因此,文字42(或fromInteger 42)可以返回IntDouble或任何其他Num实例,具体取决于调用它的上下文。< / p>

答案 2 :(得分:1)

我在这里对术语有点特别,因为我认为你使用的词背叛了一些关于Haskell如何运作的误解。

  

fromIntegral返回Num数据类型。

更确切地说,fromIntegral将任何具有class Integral实例的类型作为输入,并且可以返回作为class Num实例的任何类型。前奏定义如下:

fromIntegral :: (Integral a, Num b) => a -> b
fromIntegral = fromInteger . toInteger

具有Integral实例的类型实现toInteger函数,所有具有Num实例的类型实现fromIntegerfromIntegral使用与toInteger实例关联的Integral a将类型a的值转换为整数。然后,它使用fromInteger实例中的Num b将该Integer转换为类型b的值。

  

但似乎Num能够强制使用Double或Integer而没有任何问题。

每次使用haskell功能时,它都会被扩展&#34;。它的定义代替函数调用,并且使用的参数被替换为定义。每次在不同的上下文中展开时,它的类型变量都可以有不同的类型。因此,每次扩展函数时,它都会采用某些具体类型并返回某种具体类型。它不会返回在以后某个时间被强迫的无类型的东西。

  

类似地,read函数能够返回适合其类型签名所需的任何内容。

read :: Read a => String -> a

readString作为输入,可以在任何返回class Read实例存在的类型值的上下文中使用。当在程序执行期间扩展它时,这种类型是已知的。它使用Read a实例中的特定定义将字符串解析为正确的类型。