class 函数的实例选择 return 值

class instance selection of a function return value

我想打印 return 类型的函数(在本例中为“整数”):

{-# LANGUAGE FlexibleInstances #-}

import Data.Default

class HasReturnType a where
  getReturnType :: a -> String

instance Default a => HasReturnType (a->b) where
  getReturnType f = getReturnType (f def)

instance HasReturnType Integer where
  getReturnType _ = "Integer"

instance {-# Overlappable #-} HasReturnType a where
  getReturnType _ = "<unmatched case>"

inc :: Integer -> Integer
inc = (+1)

main = do
  putStrLn $ getReturnType inc

而是打印“”。这对我来说似乎很奇怪,因为 inc::Integer->Integer 的 return 类型显然是 Integer.

是否可以匹配像这样的函数调用的 return 值类型的实例?

(这个例子很傻,它是一个基于更复杂事物的玩具片段。我只是想了解为什么它与更具体的实例不匹配。)

你的例子不正确。 唯一有效的代码路径是通过默认情况。它使类型类实例解析短路。

一个 fill 做你期望的固定例子是:

{-# Language FlexibleInstances #-}

import Data.Typeable

class Default a where
  def :: a

instance Default Integer where
  def = 1

class HasReturnType a where
  getReturnType :: a -> String

instance (Default a, Typeable b) => HasReturnType (a->b) where
  getReturnType f = show . typeOf $ f def

instance  {-# Overlappable #-} HasReturnType a where
  getReturnType _ = "<unmatched case>"

instance HasReturnType Integer where
  getReturnType _ = "Integer"

inc :: Integer -> Integer
inc = (+1)

main = do
  putStrLn $ getReturnType inc
    {-# LANGUAGE  FlexibleInstances, ScopedTypeVariables  #-}

    module FuncReturn  where
    
        class HasReturnType a  where
            getReturnType :: a -> String
        instance HasReturnType b => HasReturnType (a -> b)  where
            getReturnType f = getReturnType $ f undefined
    --  instance HasReturnType b => HasReturnType (a -> b)  where
    --      getReturnType f = getReturnType (undefined :: b)
                          -- needs ScopedTypeVariables ^^^^    

        instance HasReturnType Integer  where
            getReturnType _ = "Integer"
        instance HasReturnType Int  where
            getReturnType _ = "Int"
        instance HasReturnType String  where
            getReturnType _ = "String"
        instance HasReturnType Bool  where
            getReturnType _ = "Bool"
        
        instance {-# OVERLAPPABLE #-} HasReturnType ab  where
            getReturnType _ = "<unmatched case>"

-- getReturnType 长度===> "Int"

-- getReturnType (&&) ===> "Bool"

-- getReturnType (+) ===> 错误 - 未解析的重载类型:(Num a, hasReturnType a) => [Char]

    inc :: Integer -> Integer
    inc = undefined               -- doesn't need a binding

-- getReturnType inc ===> "整数"

比较您的实例:

instance (Default a) => HasReturnType (a->b) where
  getReturnType f = getReturnType (f def)

使用此变体(差异已加下划线):

instance (Default a, HasReturnType b) => HasReturnType (a->b) where
                     ---------------
  getReturnType f = getReturnType (f def)

在前一个实例中,调用getReturnType (f def) 需要解决约束HasReturnType b。 GHC 立即尝试解决这个问题,当 b 仍然未知时,唯一适用的实例是通用的“不匹配的案例”,因此它致力于解决这个问题。

相比之下,后一个实例我们可以使用更大的上下文来解决约束:这使得 GHC 选择那个,有效地延迟了从这个调用点到 main 中的实例的选择。因此有效。

经验法则:GHC 尝试在每个调用点解决约束。如果此时您不想提交到特定实例,则需要在上下文中提供约束,以便延迟选择。 (当然,如果我们不使用重叠实例,GHC 提交实例的确切点是无关紧要的。)