Haskell中的有限状态传感器?

Haskell中的有限状态传感器?,haskell,state-machine,transducer,Haskell,State Machine,Transducer,我一直在想,是否有一种方法可以用惯用的方式定义和使用Haskell 您可以将FST作为生成器(它生成{x1,x2}类型的输出),或作为识别器(给定{x1,x2}类型的输入,如果它属于有理关系,它将识别它),或作为转换器(给定输入磁带,它将其转换为输出磁带)。代表性是否会因方法的不同而变化 也可以通过指定重写规则来生成FST模型吗?例如,创建一个DSL来模拟重写规则,然后创建一个函数createFST::[Rule]->FST 我能找到的最近的是Kmett、Bjarnason和Cough的机器库:

我一直在想,是否有一种方法可以用惯用的方式定义和使用Haskell

您可以将FST作为生成器(它生成{x1,x2}类型的输出),或作为识别器(给定{x1,x2}类型的输入,如果它属于有理关系,它将识别它),或作为转换器(给定输入磁带,它将其转换为输出磁带)。代表性是否会因方法的不同而变化

也可以通过指定重写规则来生成FST模型吗?例如,创建一个DSL来模拟重写规则,然后创建一个函数
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) }
机器交替地将A
b
输出到输出流,并从输入流读取输入
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
s
m
是表示计算不需要任何来自底层
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的主题。明确要求图书馆或资源推荐是不恰当的,但描述具体问题和寻求解决方案(可能涉及图书馆)是可以接受的。询问做某事的最佳方式通常过于宽泛或基于观点。要求做某事的方法仍然会导致高质量的结果