Haskell中的有限状态传感器?
我一直在想,是否有一种方法可以用惯用的方式定义和使用Haskell 您可以将FST作为生成器(它生成{x1,x2}类型的输出),或作为识别器(给定{x1,x2}类型的输入,如果它属于有理关系,它将识别它),或作为转换器(给定输入磁带,它将其转换为输出磁带)。代表性是否会因方法的不同而变化 也可以通过指定重写规则来生成FST模型吗?例如,创建一个DSL来模拟重写规则,然后创建一个函数Haskell中的有限状态传感器?,haskell,state-machine,transducer,Haskell,State Machine,Transducer,我一直在想,是否有一种方法可以用惯用的方式定义和使用Haskell 您可以将FST作为生成器(它生成{x1,x2}类型的输出),或作为识别器(给定{x1,x2}类型的输入,如果它属于有理关系,它将识别它),或作为转换器(给定输入磁带,它将其转换为输出磁带)。代表性是否会因方法的不同而变化 也可以通过指定重写规则来生成FST模型吗?例如,创建一个DSL来模拟重写规则,然后创建一个函数createFST::[Rule]->FST 我能找到的最近的是Kmett、Bjarnason和Cough的机器库:
createFST::[Rule]->FST
我能找到的最近的是Kmett、Bjarnason和Cough的机器库:
但是我似乎没有意识到如何用机器
为FST建模。我认为正确的方法类似于他们定义Moore和Mealy机器的方式:将FST定义为不同的实体,但提供一个自动机的实例,以便能够将其用作机器
我还发现了一些其他选项,但它们以一种简单的方式定义它(如中)。这并不能让我信服,因为我想知道是否有更好的方法可以习惯性地利用Haskell类型系统的优势(比如Moore和Mealy机器是如何在机器库中定义的).机器交替地从输入流A
读取A
,并将b
输出到输出流。它首先读取,然后在每次读取后输出一次
newtype Mealy a b = Mealy { runMealy :: a -> (b, Mealy a b) }
机器交替地将Ab
输出到输出流,并从输入流读取输入A
。它从输出b
开始,然后在每次输出后读取一次
data Moore a b = Moore b (a -> Moore a b)
FST要么读取输入,要么写入输出,要么停止。它可以在一行中读取任意次数,也可以在一行中写入任意次数
data FST a b
= Read (a -> FST a b)
| Write (b, FST a b)
| Stop
来自机器的FST
的等价物是。它的定义有点分散。为了简化讨论,我们将暂时忘记过程
,从内到外进行探索
基函子
为了描述什么是进程
,我们首先要注意到目前为止所有三台机器中的一种模式。它们中的每一个都递归地提到自己“下一步该做什么”。我们将用任何类型的next
替换“下一步做什么”。Mealy
机器在将输入映射到输出时,还提供要运行的下一台机器
newtype MealyF a b next = MealyF { runMealyF :: a -> (b, next) }
data MooreF a b next = MooreF b (a -> next)
Moore
机器在输出并请求输入后,计算出要运行的下一台机器
newtype MealyF a b next = MealyF { runMealyF :: a -> (b, next) }
data MooreF a b next = MooreF b (a -> next)
我们可以用同样的方法编写FST
。当我们从输入中读取时,我们将根据输入确定下一步要做什么。当我们向输出写入
时,我们还将提供输出后的下一步操作。当我们停下来时,下一步就没什么可做的了
data FSTF a b next
= Read (a -> next)
| Write (b, next)
| Stop
这种消除显式递归的模式在Haskell代码中反复出现,通常称为“基函子”。在machines包中,基本函子为。与我们的代码相比,Step
已将输出的类型变量重命名为o
,在r
旁边做什么,读取wait
,写入Yield
data Step k o r
= forall t. Await (t -> r) (k t) r
| Yield o r
| Stop
wait
ing比Read
稍微复杂一点,因为a可以从多个源读取。对于只能从单个源读取的过程
es,k
应用于特定类型,这是第二种是第一种类型的证明。对于过程
读取输入a
,k
将是是a
data Step (Is a) o r
= forall t. Await (t -> r) (Is a t) r
| Yield o r
| Stop
type Process a b = Machine (Is a) b
type ProcessT m a b = MachineT m (Is a) b
所有t.
的存在量化是一个重要的概念。在见证了a~t
之后,这就变成了
data Step (Is a) o r
= forall t ~ a. Await (t -> r) Refl r
| Yield o r
| Stop
如果我们将t
与a
统一,并删除始终相同的Refl
构造函数,这看起来就像我们的FSTF
data Step (Is a) o r
= Await (a -> r) r
| Yield o r
| Stop
在wait
中,下一步要做的额外r
是在没有更多输入时下一步要做的事情
type Process a b =
Await (a -> Process a b) (Process a b)
| Yield b (Process a b)
| Stop
机器变压器`
机器变压器使Step
看起来几乎像我们的FST
。它说:“一台机器在某个单子m
上运行,就是在该单子中执行下一步步骤的操作。每一步之后执行的下一步就是另一个机器
。”
总的来说,专门针对我们的类型,这看起来像
newtype MachineT m (Is a) o =
MachineT m (
Await (a -> MachineT m (Is a) o) (MachineT m (Is a) o)
| Yield o (MachineT m (Is a) o)
| Stop
)
机器
是一台纯机器
newtype MachineT m k o = MachineT { runMachineT :: m (Step k o (MachineT m k o)) }
type Machine k o = forall m. Monad m => MachineT m k o
通用量化全面Monad
sm
是表示计算不需要任何来自底层Monad
的东西的另一种方式。这可以通过替换m
看到
type Machine k o =
MachineT Identity (
Await (a -> MachineT Identity k o) (MachineT Identity k o)
| Yield o (MachineT Identity k o)
| Stop
)
过程
Process
或ProcessT
是只读取单一类型输入的机器
或机器
,是一种
data Step (Is a) o r
= forall t. Await (t -> r) (Is a t) r
| Yield o r
| Stop
type Process a b = Machine (Is a) b
type ProcessT m a b = MachineT m (Is a) b
在删除所有始终相同的中间构造函数后,进程
具有以下结构。此结构与我们的FST
完全相同,只是在没有更多输入的情况下添加了“下一步要做什么”
type Process a b =
Await (a -> Process a b) (Process a b)
| Yield b (Process a b)
| Stop
ProcessT
变量有一个m
包裹在它周围,这样它就可以在每个步骤的monad中起作用
过程
对状态传感器建模。这个问题需要编辑,才能成为StackOverflow的主题。明确要求图书馆或资源推荐是不恰当的,但描述具体问题和寻求解决方案(可能涉及图书馆)是可以接受的。询问做某事的最佳方式通常过于宽泛或基于观点。要求做某事的方法仍然会导致高质量的结果