首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >EDSL:s中的基元导出运算和组合子

EDSL:s中的基元导出运算和组合子
EN

Stack Overflow用户
提问于 2014-08-31 16:30:19
回答 1查看 192关注 0票数 4

我最近考试不及格,主要是因为一个电子EDSL问题。我没有理解这些概念,所以我想这就是我失败的原因。我想我的老师的解释是为了让我理解抽象,所以我想知道是否有人能更清楚地解释它。

我想知道是否有人能简要解释一下EDSL的组件是什么,以及它们的特点是什么。在我们的过程中,我们经历了DSL的浅埋和深嵌入,并查看了DSL的以下构建块:

  1. 构造函数
  2. 组合子(原语和派生)
  3. 运行函数

我认为构造函数和运行函数是更不言自明的,所以我更感兴趣的是,是什么使组合子派生或原语。如果有人会解释其他的概念,那也没什么坏处。以下是我们讲座中的一个例子,供大家参考。它是用于创建信号的DSL的一种浅表实现:

代码语言:javascript
运行
复制
module Signal.Shallow
( Time
-- | the 'Signal' type is abstract
, Signal  
-- * Smart constructors
, constS, timeS
-- * Combinators
, ($$), mapT
-- * Derived operation
, mapS
-- * Run function
, sample
) where

-- * Smart constructors
constS :: a -> Signal a
timeS  ::      Signal Time
-- * Combinators
($$)   :: Signal (a -> b) -> Signal a -> Signal b
mapT   :: (Time -> Time)  -> Signal a -> Signal a
-- * Derived operation
mapS   :: (a -> b)        -> Signal a -> Signal b
-- * Run function
sample :: Signal a -> Time -> a  

type Time = Double
newtype Signal a = Sig {unSig :: Time -> a}

-- | The constant signal.
constS x = Sig (const x)

-- | The time signal
timeS = Sig id

-- | Function application lifted to signals.
fs $$ xs = Sig (\t -> unSig fs t  (unSig xs t))
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-08-31 17:02:38

原语组合器是在DSL中内置的,用基本语言(即Haskell)定义的。DSL通常是围绕抽象类型-a类型构建的,其实现对最终用户是隐藏的。完全不透明。由语言表示的原始组合器需要知道抽象是如何实现的。

另一方面,派生组合子可以在DSL中的其他组合子中实现。它不需要知道任何关于抽象类型的信息。换句话说,派生组合器是您可以自己编写的。

这与Haskell本身中的原始类型的概念非常相似。例如,您不能自己实现IntInt操作(如+ )。这些都需要内置到编译器中的东西才能工作,因为数字是特殊处理的。另一方面,Bool并不是原始的;您可以将它写成一个库。

代码语言:javascript
运行
复制
data Bool = True | False -- ... you can't do this for Int!

除了编译器实际上是您的Haskell库之外,DSLs的“原语”和“派生”都是相同的概念。

在您的示例中,Signal是一种抽象类型。它是作为一个函数Time -> a实现的,但是该信息并不是从模块导出的。将来,您(作为DSL的作者)可以自由地更改Signal的实现方式。(事实上,您可能真的想:这不是一个有效的表示,而且使用Double的时间是非常困难的。)

$$这样的函数是原始的,因为它依赖于知道SignalTime -> a。当您更改Signal的表示时,您将不得不重写$$。此外,库的用户将无法实现$$本身。

另一方面,mapS是一个派生的操作,因为它可以完全按照导出的其他内容编写。它不需要了解任何关于Signal的特殊信息,甚至可以由库的一个用户编写。该实现可以类似于:

代码语言:javascript
运行
复制
mapS f signal = constS f $$ signal

请注意它是如何使用constS$$的,但永远不要打开signal。如何解包信号的知识完全隐藏在这两个函数中。mapS是“派生的”,因为它只是在DSL中编写的,而不需要任何低于抽象级别的东西。当您更改Signal的实现时,mapS仍然可以正常工作:您只需要正确地更新constS$$,就可以免费获得mapS

因此:原语组合器是直接用您的语言构建的,需要知道它的内部实现细节。派生组合子纯粹是用您的语言编写的,不依赖于任何这些内部细节。它们只是一些方便的函数,可以很容易地由库的最终用户编写。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25593992

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档