【问题标题】:Recursive type synonyms in Haskell - 'cycle in type synonym declarations'Haskell中的递归类型同义词-“类型同义词声明中的循环”
【发布时间】:2016-05-24 17:06:51
【问题描述】:

我目前正在阅读 CAR Hoare 的 CSP Book,并尝试使用 Haskell 实现其早期示例。

本书首先定义了一个进程代数——本质上,进程接受事件并返回另一个进程或一个符号 (bleep),表明该进程不参与此事件。 STOP 进程是为任何事件返回 bleep 的进程。

这本书建议您在 LISP 中执行此操作,因此我使用了 Racket。 STOP的定义很简单:

(define (STOP event) 'bleep)

as 是一个“自动售货机”进程,它只接受事件 coin 并返回 STOP

(define (coin-to-stop event)
  (case event
    ['coin STOP]
    [else 'bleep]))

然后我尝试在 Haskell 中实现这些相同的概念。我们没有像 Racket 这样的符号,所以让我们定义Event

data Event = Ev String deriving (Eq)

与 Racket 不同,我们不能只是捏造 'bleep 和进程之间的区别,所以我们将使用 Maybe 来定义进程的类型:

type Process = Event -> Maybe Process

其中Just p对应一个进程,Nothing对应'bleep

现在我们可以定义STOP进程:

stop :: Process
stop _ = Nothing

以及“自动售货机”流程:

coinToStop :: Process
coinToStop (Ev "coin") = Just stop
coinToStop _           = Nothing

不幸的是,这不能编译,因为你不能有循环类型定义:

Cycle in type synonym declarations:
  src\Csp.hs: type Process = Event -> Maybe Process

我玩了一会儿newtype,但我不太明白我在那里做什么。

我意识到我可以使用以下方法实现大致等效的解决方案:

data ProcResult = P (Maybe Process)
type Process = Event -> ProcResult

但这似乎不必要地难看。

在 Haskell 中表示 Process 概念的正确方法是什么?

【问题讨论】:

  • newtype Process = Process (Event -> Maybe Process) 应该可以工作。
  • 您可能想查看 chp 包 - 似乎他们将进程定义为 monad。
  • 你的签名好像错了(stop, coinToStop 带参数你定义它们为常量)

标签: haskell types


【解决方案1】:

Haskell 有三种类型定义:

  1. data:定义“成熟”的数据类型。
  2. newtype:定义一个“同构”类型,类似于不透明类型的同义词
  3. type:定义一个透明类型的同义词。就像 C/C++ 中的 typedef

所以您正在使用type 并尝试定义递归类型同义词:

type Process = Event -> Maybe Process

嗯,Haskell 中的一条规则是,在任何情况下,如果你有一个 type 同义词,你可以用它的扩展替换它,并且程序的工作原理是一样的。 Haskell 将扩展type 同义词以找出它们代表的类型。所以当你写这个时:

stop :: Process

你要求 Haskell 以这种方式扩展它:

stop :: Event -> Maybe Process
stop :: Event -> Maybe (Event -> Maybe Process)
stop :: Event -> Maybe (Event -> Maybe (Event -> Maybe Process))
     .
     .
     .

长话短说,Haskell 中的type 同义词根本不允许递归。 newtypedata 被允许递归,所以你应该在这里使用 newtype

【讨论】:

    【解决方案2】:

    感谢n.m.,我想出了一个解决方案:

    data Event = Ev String deriving (Eq)
    newtype Process = Process { run :: Event -> Maybe Process }
                      deriving (Show)
    
    stop :: Process
    stop = Process (const Nothing)
    
    coin :: Event
    coin = Ev "coin"
    
    coinAccepter :: Process
    coinAccepter = Process (\x -> case x of 
                                    (Ev "coin") -> Just stop
                                    _           -> Nothing)
    
    prefix :: Event -> Process -> Process
    prefix c p = Process (\x -> if x == c then Just p else Nothing)
    

    现在该去学习如何将runs 与bind 链接在一起...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-16
      • 2023-03-18
      • 2018-05-01
      相关资源
      最近更新 更多