代码之家  ›  专栏  ›  技术社区  ›  Wyzard

编写具有通用量化返回类型的函数

  •  2
  • Wyzard  · 技术社区  · 15 年前

    如果我写

    foo :: (Num a) => a
    foo = 42
    

    bar :: (Num a) => a
    bar = (42 :: Int)
    

    它告诉我期望的类型 a 与推断类型不匹配 Int . 我不太明白为什么,因为 内景 是类的实例 Num 那个 代表。

    我在尝试编写一个函数时遇到了同样的情况,这个函数可以归结为问题的核心,大致如下所示:

    -- Note, Frob is an instance of class Frobbable
    getFrobbable :: (Frobbable a) => Frob -> a
    getFrobbable x = x
    

    4 回复  |  直到 14 年前
        1
  •  11
  •   luqui    15 年前

    案例,即当涉及函数时 论据 而不是 结果 . 签名:

    bar :: (Num a) => a
    

    意味着 获取以选择类型 a ,前提是它是 Num . 所以在这里,来电者可以选择打电话 bar :: Int bar :: Double bar :: (Num a) => a 任何 bar 不知道选择了什么特定类型。

    相反的情况是完全相同的,它只是符合面向对象程序员的直觉在这种情况下。如。

    baz :: (Num a) => a -> Bool
    

    意味着 来电者 获取以选择类型 baz 不知道选择了什么特定类型。

    如果需要让被调用方选择结果类型,只需更改函数的签名即可反映这一知识。如。:

    bar :: Int
    

    或者在你的 getFrobbable getFrobbable :: Frob -> Frob (Frobbable a) 约束发生时 Frob 弗罗布 相反。

    a mistake

        2
  •  3
  •   intoverflow    15 年前

    -- Note, Frob is an instance of class Frobbable
    getFrobbable :: (Frobbable a) => Frob -> a
    getFrobbable x = x
    

    这基本上是一个铸造操作。这需要一段时间 Frob Frobbable .

    哈斯克尔有一个成语可以用来实现这一点。它需要 ExistentialQuantification

    {-# LANGUAGE ExistentialQuantification #-}
    module Foo where
    
    class Frobbable a where
      getInt :: a -> Int
    
    data Frob = Frob Int
    
    instance Frobbable Frob where
      getInt (Frob i) = i
    
    data FrobbableWrapper = forall a . Frobbable a => FW a
    
    instance Frobbable FrobbableWrapper where
      getInt (FW i) = getInt i
    

    关键部分是 FrobbableWrapper 数据结构。使用它,您可以编写以下版本的 getFrobbable

    getFrobbable :: Frobbable a => a -> FrobbableWrapper
    getFrobbable x = FW x
    

    Frobbable a => [a] 不允许你混合不同的 起泡的 ,列表 [FrobbableWrapper] 当然会。

    为什么你发布的代码是不允许的

    现在,你为什么不能按原样写你的施法步骤呢?这都是关于如果你的原作 可冻结的 函数被允许进行类型检查。

    方程式 getFrobbable x = x x

    让我们比较一下 可冻结的 另一个物体。考虑

    anonymousFrobbable :: Frobbable a => a
    anonymousFrobbable = undefined
    

    (代码涉及 undefined

    现在假设有人来介绍一个数据定义和一个函数,比如

    data Frob2 = Frob2 Int Int
    
    instance Frobbable Frob2 where
      getInt (Frob2 x y) = y
    
    useFrobbable :: Frob2 -> [Int]
    useFrobbable fb2 = []
    

    *Foo> useFrobbable anonymousFrobbable 
    []
    

    没有问题:签名 anonymousFrobbable 意思是“你选一个Frobbable的例子,我就假装我是那种类型的。”

    如果我们试着用你的版本 可冻结的 ,一个像

    useFrobbable (getFrobbable someFrob)
    

    1. someFrob 必须是类型 ,因为它是给 可冻结的 .
    2. (getFrobbable someFrob) Frob2 因为它是给 useFrobbable
    3. 但根据公式 getFrobbable someFrob = someFrob getFrobbable someFrob 萨姆弗罗布

    因此,系统得出结论 弗罗布 弗罗布2 可冻结的 你贴的不是打字检查。

        3
  •  2
  •   yatima2975    15 年前

    同样值得注意的是 42 实际上代表 fromInteger (42 :: Integer) ,这真的有类型 (Num a) => a Haskell Report on numeric literals .

        4
  •  0
  •   Anthony    15 年前

    我有点搞不清楚你想做什么,但如果你只是想让调用者使用返回值来驱动实例选择,那么这就是正常的typeclass。

    data Frob = Frob Int Float
    
    class FrobGettable a where
        getFrobbable :: Frob -> a
    
    instance FrobGettable Int where
        getFrobbable (Frob x _) = x
    
    instance FrobGettable Float where
        getFrobbable (Frob _ y) = y
    
    instance FrobGettable Char where
        getFrobbable _ = '!'
    
    frob = Frob 10 3.14
    
    test1 :: Float
    test1 = getFrobbable frob * 1.1
    
    test2 :: Int
    test2 = getFrobbable frob `div` 4
    
    test3 = "Hi" ++ [getFrobbable frob]
    

    我们可以用GHCi看看我们有什么,

    *Main> :t getFrobbable
    getFrobbable :: (FrobGettable a) => Frob -> a
    
    推荐文章