gpt4 book ai didi

haskell - 我将如何以可扩展的方式抽象命令/响应?

转载 作者:行者123 更新时间:2023-12-02 02:38:52 31 4
gpt4 key购买 nike

在尝试在 Haskell 中进行一些领域驱动设计时,我发现自己遇到了这个问题:

data FetchAccessories = FetchAccessories
data AccessoriesResponse = AccessoriesResponse

data FetchProducts = FetchProducts
data ProductsResponse = ProductsResponse

type AccessoryHandler = FetchAccessories -> AccessoriesResponse
type ProductHandler = FetchProducts -> ProductsResponse

handle :: Handler -- Not sure how to do this abstraction
handle FetchAccessories = AccessoriesResponse
handle FetchProducts = ProductsResponse

someFn :: AccessoriesResponse -- Ideally
someFn = handle FetchAccessories

我想做的是将单个 Fetch* 与单个 Response* 绑定(bind)在一起,并提供足够的信息以便编译器知道我是否调用 handle FetchAccessories , 只能返回 AccessoriesResponse .

编辑:

更理想的是,这将在没有注释的情况下工作,产品和配件具有适当的类型推断:
biggerFn =
let products = handle FetchProducts
accessories = handle FetchAccessories
in
undefined -- do business things

最佳答案

如前所述,这正是类型类的工作。类型类是一种构造,它允许您将几种类型联系在一起,并在这些类型上定义一些函数。

在您的情况下,我们可以定义一个类 Handler像这样:

class Handler request response where
handle :: request -> response

在这里, requestresponse是类型变量,代表两种类型,它们被我们的类“绑定(bind)在一起”,以及一个函数 handle这需要一个并返回另一个。

接下来,我们可以为您的两种情况定义此类的实例:
instance Handler FetchAccessories AccessoriesResponse where
handle FetchAccessories = AccessoriesResponse

instance Handler FetchProducts ProductsResponse where
handle FetchProducts = ProductsResponse

然后我们就可以使用函数了:
someFn :: AccessoriesResponse
someFn = handle FetchAccessories

(请注意,您需要启用 MultiParamTypeClasses 才能使用此功能)

回复您的评论:我想知道是否有某种方法可以避免 someFn 上的注释(因为 ghc 似乎非常接近知道)

问题是,GHC 实际上并不接近知道。你知道 AccessoriesResponse仅适用于 FetchAccessories ,但就 GHC 而言,这不一定是真的。毕竟,您可以继续添加另一个类实例,如下所示:
instance Handler FetchAccessories String where
handler FetchAccessories = "foo"

现在事实证明 handle FetchAccessories可能意味着 AccessoriesResponse"foo" . GHC 无法为您做出决定。

但是您可以明确地告诉它,对于每种请求类型,只能有一种响应类型。这称为“功能依赖”(您需要为此启用 FunctionalDependencies),语法如下:
class Handler request response | request -> response where
handler :: request -> response

这将告诉 GHC responserequest 唯一确定并且会产生两个实际后果: (1) GHC 将拒绝二审 Handler FetchAccessories String从我上面的例子中,提示它违反了函数依赖,并且 (2) GHC 将能够弄清楚 response 是什么只要知道 request .

特别是,这意味着您可以省略 someFn 上的类型签名。 .

在相关的说明中,您可能也可能不想做相反的事情:对于每个响应,只能有一个请求。为此,您可以指定两个功能依赖项:
class Handler request response | request -> response, response -> request where

(根据您的评论,以下内容不再相关,但我将在此留作记录)

但是,我怀疑您的实际意思是另一种模型。我怀疑你的意思是一个模型说“请求可以是产品或附件,响应可以是产品或附件, handle 函数会将任何给定的请求转换为相应的响应"

如果这确实是您的意思,那么合适的模型将是 sum 类型:
data Fetch = FetchAccessories | FetchProducts
data Response = AccessoriesResponse | ProductsResponse

handle :: Fetch -> Response
handle FetchAccessories = AccessoriesResponse
handle FetchProducts = ProductsResponse

关于haskell - 我将如何以可扩展的方式抽象命令/响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61682008/

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