gpt4 book ai didi

Haskell 子类型类需要 UndecidableInstances?

转载 作者:行者123 更新时间:2023-12-04 04:06:48 27 4
gpt4 key购买 nike

考虑以下代码示例:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-} -- Is there a way to avoid this?

-- A generic class with a generic function.
class Foo a where
foo :: a -> a

-- A specific class with specific functions.
class Bar a where
bar :: a -> a
baz :: a -> a

-- Given the specific class functions, we can implement the generic class function.
instance Bar a => Foo a where
foo = bar . baz

-- So if a type belongs to the specific class...
instance Bar String where
bar = id
baz = id

-- We can invoke the generic function on it.
main :: IO ()
main =
putStrLn (foo "bar")

(我的实际代码要复杂得多;这是演示该模式的最小简化案例。)

我不清楚为什么 UndecidableInstances这里需要 - 类型参数 aBar a => Foo a 的两边出现一次,所以我希望事情“正常工作”。我显然在这里遗漏了一些东西。但无论如何,有没有办法在不使用 UndecidableInstances 的情况下做到这一点? ?

最佳答案

您可以采取几种方法;我认为您没有提供足够的上下文来确定哪个是最合适的。如果您使用 GHC-7.4,您可能想尝试 DefaultSignatures扩大。

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DefaultSignatures #-}

-- A generic class with a generic function.
class Foo a where
foo :: a -> a
default foo :: Bar a => a -> a
foo = bar . baz

-- A specific class with specific functions.
class Bar a where
bar :: a -> a
baz :: a -> a

instance Bar String where
bar = id
baz = id

instance Foo String

main :: IO ()
main =
putStrLn (foo "bar")

你仍然需要声明一个类型是 Foo 的一个实例。 ,但您不需要重复方法声明,因为将使用默认实现。

另一种相当轻量级的方法是使用新类型。如果您有需要 Foo 的功能例如,您可以包装 Bar新类型中的实例。
newtype FooBar a = FooBar { unFooBar :: a }

instance Bar a => Foo (FooBar a) where
foo = FooBar . bar . baz . unFooBar

-- imported from a library or something...
needsFoo :: Foo a => a -> b

myFunc = needsFoo (FooBar someBar)

或者,您可以通过替换 foo 来解决问题。具有正常功能,或为 Bar 制作专用版本实例:
-- if every `Foo` is also a `Bar`, you can just do this.  No need for `Foo` at all!
foo :: Bar a => a -> a
foo = bar . baz

-- if most `Foo`s aren't `Bar`s, you may be able to use this function when you have a `Bar`
fooBar :: Bar a => a -> a
foo = bar . baz

如果它们适合您的情况,这些可能是最好的解决方案。

另一种选择是声明每个 Foo手动实例。尽管可能有很多不同的可以想象的实例,但代码库只有少数实际使用的实例是相当普遍的。如果这里是真的,那么只写出您需要的 3 或 4 个实例而不是尝试实现更通用的解决方案可能会减少工作量。

作为最后的手段,您可以使用类似于原始代码的东西,但您还需要 OverlappingInstances让它工作(如果你不需要 OverlappingInstances ,那么你不需要 Foo 类)。这是允许 GHC 在有多个可用匹配项时选择“最具体的实例”的扩展。这或多或少会起作用,尽管您可能无法得到您期望的结果。
class Foo a where
foo :: a -> a

class Bar a where
bar :: a -> a
baz :: a -> a

instance Bar String where
bar = id
baz = id

instance Bar a => Foo a where
foo = bar . baz

instance Foo [a] where
foo _ = []

main :: IO ()
main =
print (foo "foo")

现在 main打印一个空字符串。有两个 Foo实例,对于 a[a] .后者更具体,因此它被选为 foo "foo"因为字符串的类型为 [Char] ,尽管您可能想要前者。所以现在你还需要写
instance Foo String where
foo = bar . baz

此时您不妨省略 Bar a => Foo a完全实例。

关于Haskell 子类型类需要 UndecidableInstances?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11707171/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com