在免费monad的上下文中,Haskell是否有等效的注入 [英] Is there an inject equivalent for Haskell in the context of free monads

查看:82
本文介绍了在免费monad的上下文中,Haskell是否有等效的注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试翻译此Scala的cats示例关于免费撰写单子.

I'm trying to translate this Scala's cats example about composing free monads.

该示例的要点似乎是将不同的关注点分解为不同的数据类型:

The gist of the example seems to be the decomposition of separate concerns into separate data types:

data Interact a = Ask (String -> a) | Tell String a deriving (Functor)

data DataOp = AddCat String | GetAllCats [String] deriving (Functor)

type CatsApp = Sum Interact DataOp

在没有这两个单独的问题的情况下,我将为Interact操作构建语言",如下所示:

Without having these two separate concerns, I would build the "language" for Interact operations as follows:

ask :: Free Interact String
ask = liftF $ Ask id

tell :: String -> Free Interact ()
tell str = liftF $ Tell str ()

但是,如果我想在也使用DataOp的程序中使用asktell,则无法使用上述类型定义它们,因为这样的程序将具有类型:

However, if I want to use ask and tell in a program that also uses DataOp I cannot define them with the types above, since such a program will have type:

program :: Free CatsApp a

cats中,对于tellask操作的定义,它们使用InjectK类和Free中的inject方法:

In cats, for the definition of the tell and ask operations they use an InjectK class, and an inject method from Free:

class Interacts[F[_]](implicit I: InjectK[Interact, F]) {
  def tell(msg: String): Free[F, Unit] = Free.inject[Interact, F](Tell(msg))
  def ask(prompt: String): Free[F, String] = Free.inject[Interact, F](Ask(prompt))
}

让我感到困惑的是,仿函数的位置信息(DataOp在左侧,Interact在右侧)似乎无关紧要(很好).

What puzzles me is that somehow the positional information of the functors (DataOp is on the left, Interact is on the right) seems to be irrelevant (which is quite nice).

是否有类似的类型类和函数可用于使用Haskell优雅地解决此问题?

Are there similar type-classes and functions that could be used to solve this problem in an elegant manner using Haskell?

推荐答案

点菜"数据类型 .您演示的Scala库看起来像是对原始Haskell的忠实翻译.要点是,您编写一个类来表示包含"函子sub的函子sup之间的关系:

This is covered in Data Types à la Carte. The Scala library you demonstrated looks like a fairly faithful translation of the original Haskell. The gist of it is, you write a class representing a relationship between a functor sup which "contains" a functor sub:

class (Functor sub, Functor sup) => sub :-<: sup where
    inj :: sub a -> sup a

(这几天,您可能会使用

(These days you might use a Prism, because they can both inject and project.) Then you can use the usual technique of composing the base functors of your free monads using the functor coproduct, implement :-<: for the two cases of Sum,

instance Functor f => f :-<: f where
    inj = id
instance (Functor f, Functor g) => f :-<: (Sum f g) where
    inj = InL
instance (Functor f, Functor g, Functor h, f :-<: g) => f :-<: (Sum h g) where
    inj = InR . inj

并通过对基本函子进行抽象来使指令集可组合.

and make instruction sets composable by abstracting over the base functor.

ask :: Interact :-<: f => Free f String
ask = liftF $ inj $ Ask id

tell :: Interact :-<: f => String -> Free f ()
tell str = liftF $ inj $ Tell str ()

addCat :: DataOp :-<: f => String -> Free f ()
addCat cat = liftF $ inj $ AddCat cat ()

getCats :: DataOp :-<: f => Free f [String]
getCats = liftF $ inj $ GetCats id

现在,您可以编写同时使用InteractDataOp的程序,而无需引用特定的求和类型.

Now you can write a program which uses both Interact and DataOp without making reference to a particular sum type.

myProgram :: (Interact :-< f, DataOp :-< f) => Free f ()
myProgram = ask >>= addCat

不过,没有一个方法比标准MTL方法特别好.

None of this is particularly better than the standard MTL approach, though.

这篇关于在免费monad的上下文中,Haskell是否有等效的注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆