haskell - 如何从支持某些 API 的函数返回非具体值?

标签 haskell

我正在两个模型之间构建一个 API。我不在乎它是否返回 [] 或 Seq 或任何可折叠的东西都可以。但是如果我尝试这样做,我会得到错误。

module Main where
import Prelude hiding (foldr)
import Data.Foldable
import Data.Sequence

data Struct = Struct

main = do
  print $ foldr (+) 0 $ list Struct
  print $ foldr (+) 0 $ listFree Struct


listFree :: Foldable f => a -> f Int
listFree s = singleton 10

class TestClass a where
  list :: Foldable f => a -> f Int

instance TestClass Struct where
  list s = singleton 10

listFree 和列表定义都给出相同的错误:
TestFoldable.hs:19:12:
Could not deduce (f ~ [])
from the context (Foldable f)
  bound by the type signature for
             list :: Foldable f => Struct -> f Int
  at TestFoldable.hs:19:3-15
  `f' is a rigid type variable bound by
      the type signature for list :: Foldable f => Struct -> f Int
      at TestFoldable.hs:19:3
In the expression: [10]
In an equation for `list': list s = [10]
In the instance declaration for `TestClass Struct'

这是为什么?什么是完成我在这里尝试做的“正确”方法?

我想要完成的是对调用者隐藏实现。实际的数据结构可能是 Seq、IntMap 或其他任何东西,而且很可能不是列表。

我收到的回复说“只返回一个列表”。但这意味着转换,不是吗?如果它是一个 1,000,000 个元素的结构怎么办?仅仅因为 API 的限制而将其转换为中间数据结构似乎是一个糟糕的解决方案。

这是一个普遍的问题。如何获得符合某些 API 的返回值?隐藏具体实现,以便实现者可以自由选择最适合他们的结构,并且可以更改它而无需更改 API 的用户。

另一种说法是:如何返回接口(interface)而不是具体类型?

结语:

StackOverflow 上的 Haskell 社区是 (SuperlativeCompliment c => forall c. c)

存在量化似乎是这种情况的一般解决方案。

另一种考虑的可能性,这不是一个通用的解决方案,但可能适用于这种特定情况,可能会避免存在解决方案所需的额外包装器值是为客户端返回折叠的闭包:
list :: a -> ((Int -> b -> b) -> b -> b)
list = \f a0 -> foldr f a0 (singleton 10)

最佳答案

Why is that?



类型Foldable f => a -> f Int并不意味着该函数可能会返回它想要的任何可折叠文件。这意味着该函数将返回用户想要的任何类型。 IE。如果用户在需要列表的上下文中使用该函数,并且如果他在需要 Seq 的上下文中使用它也应该工作。由于您的定义显然不是这种情况,因此它与其类型不匹配。

And what is the "right" way to accomplish what I'm trying to do here?



最简单的方法是让你的函数返回一个列表。

但是,如果您确实需要向用户隐藏您正在使用列表的事实,最简单的方法是围绕列表创建一个包装器类型,而不是导出该类型的构造函数。 IE。就像是:
module Bla (ListResult(), list) where
data ListResult a = ListResult [a]

instance Foldable (ListResult a) where
    foldr op s (ListResult xs) = foldr op s xs

list s = ListResult [10]

现在,如果用户导入您的模块,它可以折叠 ListResult,因为它是可折叠的,但由于未导出构造函数,因此无法将其解包以获取列表。因此,如果您稍后更改 ListResult的定义为 data ListResult a = ListResult (Seq a)list也可以使用 Seq而不是列表,用户将完全看不到该更改。

关于haskell - 如何从支持某些 API 的函数返回非具体值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8155709/

相关文章:

Haskell - 找不到包

haskell - 为什么 Num 不能与 0 进行比较?

haskell - 无法安装 wx

haskell - 什么是应用效果?

函数应用: Why is $ used here?

haskell - 无法将 LoggingT 与 NoLoggingT 匹配

haskell - 这个 Haskell 代码的语法规则是什么?

list - 通过索引交换列表中的两个元素

haskell - Haskell : Parse error on “|” in otherwise

haskell - 语法树 : free monad + Bound. 范围