我正在使用Free Monads构建一个小型DSL.
我希望能够在我的DSL中拥有多态功能.
我想要构建的一个例子是:
{-# LANGUAGE TemplateHaskell #-}
import Control.Monad.Free.Church
data Queue a = Queue a
data MyDsl next =
NewQueue (Queue a -> next) |
WriteToQueue (Queue a) a next
makeFree ''MyDsl
testProgram :: F MyDsl
testProgram = do
(intQueue :: Queue Int) <- newQueue
(charQueue :: Queue Char) <- newQueue
writeToQueue intQueue 1
writeToQueue charQueue 'c'
Run Code Online (Sandbox Code Playgroud)
我编码它的方式我得到的Not in scope: type variable ‘a’
错误是有道理的.有没有办法在使用Free的DSL中拥有多态函数?
对于背景,我想这样做的原因是我可以拥有一个在幕后使用TQueue的生产解释器和一个使用内存数据结构进行测试的测试解释器.
假设我只尝试使用一个操作来实现一个非常简单的特定于域的语言:
printLine(line)
Run Code Online (Sandbox Code Playgroud)
然后我想写一个程序,它接受一个整数n作为输入,打印一些东西,如果n可以被10k整除,然后调用自己n + 1,直到n达到一些最大值N.
省略由for-comprehensions引起的所有语法噪音,我想要的是:
@annotation.tailrec def p(n: Int): Unit = {
if (n % 10000 == 0) printLine("line")
if (n > N) () else p(n + 1)
}
Run Code Online (Sandbox Code Playgroud)
从本质上讲,它将是一种"fizzbuzz".
以下是使用Scalaz 7.3.0-M7中的Free monad实现此操作的一些尝试:
import scalaz._
object Demo1 {
// define operations of a little domain specific language
sealed trait Lang[X]
case class PrintLine(line: String) extends Lang[Unit]
// define the domain specific language as the free monad of operations
type …Run Code Online (Sandbox Code Playgroud) 是否可以为实现一个MonadTransControl实例FreeT?我从以下内容开始,但陷入困境:
instance (Functor f) => MonadTransControl (FreeT f) where
newtype StT (FreeT f) r = FreeTStT r
liftWith unlift = lift $ unlift $ error "Stuck here"
restoreT inner = do
FreeTStT r <- lift inner
return r
Run Code Online (Sandbox Code Playgroud)
如果它无法实现,那么为什么并且可以通过某种方式扩展特定的自由函子实现以使其可以实现?
我正在使用免费的monad和镜头,使用免费的monad来创建我自己的IO monad版本:
data MyIO next
= LogMsg String next
| GetInput (String -> next)
deriving (Functor)
Run Code Online (Sandbox Code Playgroud)
我把它堆叠在状态monad之上,如下所示:FreeT MyIO (State GameState) a其中GameState:
data GameState = GameState { _players :: [PlayerState] }
Run Code Online (Sandbox Code Playgroud)
现在,我想要的是一种PlayerState从GameState上下文"放大"a 的方法.像这样的东西:
zoomPlayer :: Int -> FreeT MyIO (State PlayerState) a -> FreeT MyIO (State GameState) a
zoomPlayer i prog = hoistFreeT (zoom (players . element i)) prog
Run Code Online (Sandbox Code Playgroud)
但是我收到了这个错误:
No instance for (Data.Monoid.Monoid a1)
arising from a use of ‘_head’
Run Code Online (Sandbox Code Playgroud)
这个错误似乎与players …
说我有以下免费monad:
data ExampleF a
= Foo Int a
| Bar String (Int -> a)
deriving Functor
type Example = Free ExampleF -- this is the free monad want to discuss
Run Code Online (Sandbox Code Playgroud)
我知道如何使用此monad。我可以写一些不错的助手:
foo :: Int -> Example ()
foo i = liftF $ Foo i ()
bar :: String -> Example Int
bar s = liftF $ Bar s id
Run Code Online (Sandbox Code Playgroud)
所以我可以用haskell编写程序,例如:
fooThenBar :: Example Int
fooThenBar =
do
foo 10
bar "nice"
Run Code Online (Sandbox Code Playgroud)
我知道如何打印,解释等。但是如何解析呢?
是否有可能编写一个解析器来解析任意程序,例如:
foo 12
bar nice
foo 11
foo …Run Code Online (Sandbox Code Playgroud) 我不确定如何在定点之后派生出函数实例:
data FreeF f a next = PureF a | FreeF (f next) deriving (Functor)
data Mu f = In { out :: f ( Mu f ) }
newtype Free f a = Free( Mu (FreeF f a) )
instance Functor f => Functor (Free f) where
fmap h (Free (out -> PureF a)) = Free (In (PureF (h a)))
fmap h (Free (out -> FreeF fn)) = Free (In (fmap undefined undefined)) --stuck
Run Code Online (Sandbox Code Playgroud)
如果我修改Mu以接受额外的类型参数,我可以继续...直到...:
data Mu f a …Run Code Online (Sandbox Code Playgroud) 我试图在ocaml中编写一个免费的monad库,跟随haskell的Control.Monad.Free,但是我在一个点上,在hoistFree的实现中陷入困境.
hoistFree :: Functor g => (forall a. f a -> g a) -> Free f b -> Free g b
hoistFree _ (Pure a) = Pure a
hoistFree f (Free as) = Free (hoistFree f <$> f as)
Run Code Online (Sandbox Code Playgroud)
这是我翻译的尝试.
let rec hoistfree : 'b.('b t -> 'b t) -> 'a m -> 'a m =
fun f x -> match x with
| Return x -> Return x
| Free x -> Free (T.map (hoistfree f) (f …Run Code Online (Sandbox Code Playgroud) 我正在尝试在我的项目中开始使用免费的 monad,我正在努力让它变得优雅。
假设我有两个上下文(实际上我有更多) -Receipt而且User- 都对数据库进行了操作,我希望将它们的解释器分开并在最后一刻组合它们。
为此,我需要为每个操作定义不同的操作,并使用Coproduct.
这是我经过几天的谷歌搜索和阅读后的结果:
// Receipts
sealed trait ReceiptOp[A]
case class GetReceipt(id: String) extends ReceiptOp[Either[Error, ReceiptEntity]]
class ReceiptOps[F[_]](implicit I: Inject[ReceiptOp, F]) {
def getReceipt(id: String): Free[F, Either[Error, ReceiptEntity]] = Free.inject[ReceiptOp, F](GetReceipt(id))
}
object ReceiptOps {
implicit def receiptOps[F[_]](implicit I: Inject[ReceiptOp, F]): ReceiptOps[F] = new ReceiptOps[F]
}
// Users
sealed trait UserOp[A]
case class GetUser(id: String) extends UserOp[Either[Error, User]]
class UserOps[F[_]](implicit I: Inject[UserOp, F]) {
def getUser(id: String): Free[F, Either[Error, User]] = …Run Code Online (Sandbox Code Playgroud) 我正在尝试构建一个抽象语法树,允许使用 monaddo表示法进行定义,如下所示:
ast = do
Variable uint8 "i"
Function Void "f" $ do
Variable uint8 "local_y"
Comment "etc. etc."
Run Code Online (Sandbox Code Playgroud)
我在这里展示的结构是从Text.Blaze.Html中收集的,它用于定义 HTML 树。
问题分散在以下各个部分。主要问题是如何正确地做到这一点。当然,任何有助于理解此结构的输入都将受到高度赞赏。
因此,首先,这是一个虽小、有缺陷但“有效”的示例。它是一个语法树,其中包含特定类型的变量和函数的声明、注释行以及用于替换的占位符声明:
{-# LANGUAGE ExistentialQuantification #-}
module Question
where
import Control.Applicative
import Data.Monoid (Monoid, (<>))
import Data.String.Utils (rstrip)
type NumberOfBits = Word
type VariableName = String
data Type = UInt NumberOfBits
| Int NumberOfBits
| Void
uint8 = UInt 8
int8 = Int 8
instance Show Type where
show (UInt w) = "uint" <> …Run Code Online (Sandbox Code Playgroud) 我想在 doobie 中使用 for-comprehension 在一个事务中运行多个查询。就像是:
def addImage(path:String) : ConnectionIO[Image] = {
sql"INSERT INTO images(path) VALUES($path)".update.withUniqueGeneratedKeys('id', 'path')
}
def addUser(username: String, imageId: Optional[Int]) : ConnectionIO[User] = {
sql"INSERT INTO users(username, image_id) VALUES($username, $imageId)".update.withUniqueGeneratedKeys('id', 'username', 'image_id')
}
def createUser(username: String, imagePath: Optional[String]) : Future[User] = {
val composedIO : ConnectionIO[User] = for {
optImage <- imagePath.map { p => addImage(p) }
user <- addUser(username, optImage.map(_.id))
} yield user
composedIO.transact(xa).unsafeToFuture
}
Run Code Online (Sandbox Code Playgroud)
我刚开始接触 doobie(和猫),所以我对 FreeMonads 不太熟悉。我一直在尝试不同的解决方案,但为了理解工作,看起来两个块都需要返回一个cats.free.Free[doobie.free.connection.ConnectionOp,?]。
如果这是真的,有没有办法将我的 ConnectionIO[Image](来自 addImage 调用)转换为 cat.free.Free[doobie.free.connection.ConnectionOp,Option[Image]] ?
free-monad ×10
haskell ×7
monads ×3
scala ×3
scala-cats ×2
doobie ×1
dsl ×1
functor ×1
haskell-lens ×1
ocaml ×1
scalaz ×1
state-monad ×1
tree ×1