我怎样才能创建一个同时接受 Num 和 Maybe Num 的函数?

领主

我目前正在学习 Haskell 中的类型类,现在我正在尝试创建一个适用于 Maybe 和 Num 的增量函数。但是,我现在有点卡住了。有人可以帮助我朝着正确的方向发展吗?(以下错误)

编辑:我在编译期间按照编译器的建议使用 -XUndecidableInstances 和 -XFlexibleInstances 作为参数,考虑到 -XOverlappingInstances(如评论中所建议)均已弃用且似乎不起作用。

-- maybenum.hs
class SomeNum a where
  inc' :: a -> Int

instance Num a => SomeNum a where
  inc' n = inc' (Just n)

instance Num a => SomeNum (Maybe a) where
  inc' Nothing = 1
  inc' (Just n) = n + 1

main :: IO ()
main = do
  print $ inc' (Just 0)
  print $ inc' 5
  print $ inc' Nothing

这是我得到的错误:

[1 of 1] Compiling Main             ( maybenum.hs, maybenum.o )

maybenum.hs:5:12: error:
    • Overlapping instances for SomeNum (Maybe a)
        arising from a use of ‘inc'’
      Matching instances:
        instance Num a => SomeNum a -- Defined at maybenum.hs:4:10
        instance Num a => SomeNum (Maybe a) -- Defined at maybenum.hs:7:10
    • In the expression: inc' (Just n)
      In an equation for ‘inc'’: inc' n = inc' (Just n)
      In the instance declaration for ‘SomeNum a’

maybenum.hs:9:19: error:
    • Couldn't match expected type ‘Int’ with actual type ‘a’
      ‘a’ is a rigid type variable bound by
        the instance declaration at maybenum.hs:7:10
    • In the expression: n + 1
      In an equation for ‘inc'’: inc' (Just n) = n + 1
      In the instance declaration for ‘SomeNum (Maybe a)’
    • Relevant bindings include
        n :: a (bound at maybenum.hs:9:14)
        inc' :: Maybe a -> Int (bound at maybenum.hs:8:3)

maybenum.hs:13:11: error:
    • Overlapping instances for SomeNum (Maybe a1)
        arising from a use of ‘inc'’
      Matching instances:
        instance Num a => SomeNum a -- Defined at maybenum.hs:4:10
        instance Num a => SomeNum (Maybe a) -- Defined at maybenum.hs:7:10
    • In the second argument of ‘($)’, namely ‘inc' (Just 0)’
      In a stmt of a 'do' block: print $ inc' (Just 0)
      In the expression:
        do { print $ inc' (Just 0);
             print $ inc' 5;
             print $ inc' Nothing }

maybenum.hs:13:22: error:
    • Ambiguous type variable ‘a1’ arising from the literal ‘0’
      prevents the constraint ‘(Num a1)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a1’ should be.
      These potential instances exist:
        instance Num Integer -- Defined in ‘GHC.Num’
        instance Num Double -- Defined in ‘GHC.Float’
        instance Num Float -- Defined in ‘GHC.Float’
        ...plus two others
        (use -fprint-potential-instances to see them all)
    • In the first argument of ‘Just’, namely ‘0’
      In the first argument of ‘inc'’, namely ‘(Just 0)’
      In the second argument of ‘($)’, namely ‘inc' (Just 0)’

maybenum.hs:14:11: error:
    • Overlapping instances for SomeNum a0 arising from a use of ‘inc'’
      Matching instances:
        instance Num a => SomeNum a -- Defined at maybenum.hs:4:10
        instance Num a => SomeNum (Maybe a) -- Defined at maybenum.hs:7:10
      (The choice depends on the instantiation of ‘a0’
       To pick the first instance above, use IncoherentInstances
       when compiling the other instance declarations)
    • In the second argument of ‘($)’, namely ‘inc' 5’
      In a stmt of a 'do' block: print $ inc' 5
      In the expression:
        do { print $ inc' (Just 0);
             print $ inc' 5;
             print $ inc' Nothing }

maybenum.hs:14:16: error:
    • Ambiguous type variable ‘a0’ arising from the literal ‘5’
      prevents the constraint ‘(Num a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance Num Integer -- Defined in ‘GHC.Num’
        instance Num Double -- Defined in ‘GHC.Float’
        instance Num Float -- Defined in ‘GHC.Float’
        ...plus two others
        (use -fprint-potential-instances to see them all)
    • In the first argument of ‘inc'’, namely ‘5’
      In the second argument of ‘($)’, namely ‘inc' 5’
      In a stmt of a 'do' block: print $ inc' 5

maybenum.hs:15:11: error:
    • Overlapping instances for SomeNum (Maybe a2)
        arising from a use of ‘inc'’
      Matching instances:
        instance Num a => SomeNum a -- Defined at maybenum.hs:4:10
        instance Num a => SomeNum (Maybe a) -- Defined at maybenum.hs:7:10
    • In the second argument of ‘($)’, namely ‘inc' Nothing’
      In a stmt of a 'do' block: print $ inc' Nothing
      In the expression:
        do { print $ inc' (Just 0);
             print $ inc' 5;
             print $ inc' Nothing }
AJF

这是调整后的代码:

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

class SomeNum a where
  inc' :: a -> Int

instance {-# OVERLAPPABLE #-} Integral a => SomeNum a where
  inc' n = fromIntegral n + 1

instance Integral a => SomeNum (Maybe a) where
  inc' Nothing  = 1
  inc' (Just n) = fromIntegral n + 1

这正如我认为你的意图:

λ> inc' 1
2
λ> inc' (Just 1)
2
λ> inc' Nothing
1

我根据我认为您对这段代码的意图进行了一些更改。以下是对每个的解释:

第一个变化{-# OVERLAPPABLE #-}::

您说它已-XOverlappingInstances被弃用是正确的,但您没有注意到它已被弃用而支持{#- OVERLAPPABLE #-}. 这是我添加的内容:

instance {-# OVERLAPPABLE #-} (...)

这是一个必要的补充,因为您已经定义了一个单独的Numfor实例Maybe,这会导致您遇到冲突。对于我所做的更改,这实际上不是必需的,但是如果您确实将限制从 更改回IntegralNum再次,这将挽救您的跌倒。

第二个变化: Integral a =>

您不能只是从 a 转换Num为 an Int,正如您的inc'函数所暗示的那样(请记住,这Float是 的一个实例Num。)因此,我调整了限制:

instance {-# OVERLAPPABLE #-} Integral a => SomeNum a where
  inc' n = fromIntegral n + 1

这也显着简化了inc'实现。注意使用fromIntegral :: (Integral a, Num b) => a -> b. 我不完全确定这是否是有意的,但我你没有指定,所以我猜。


我希望这有帮助。如果这不完全符合您的预期,请尝试自行调整并探索这些语言扩展的行为方式。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章