Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell EDSL:s中的本原派生运算和组合子_Haskell_Dsl - Fatal编程技术网

Haskell EDSL:s中的本原派生运算和组合子

Haskell EDSL:s中的本原派生运算和组合子,haskell,dsl,Haskell,Dsl,我最近考试不及格,主要是因为EDSL问题。我没有掌握这些概念,所以我想这就是我失败的原因。我想老师的解释对我来说太抽象了,我不知道是否有人能解释得更清楚 我想知道是否有人能简单地解释一下EDSL的组成部分,以及它们的特征。在我们的课程中,我们经历了DSL的浅层和深层嵌入,并研究了DSL的以下构建块: 构造函数 组合子(原语和派生) 运行函数 我认为constructor和run函数更具自解释性,因此我更感兴趣的是理解是什么使组合子派生或原语。如果有人解释其他的概念,那也没什么坏处。这是我们讲座中

我最近考试不及格,主要是因为EDSL问题。我没有掌握这些概念,所以我想这就是我失败的原因。我想老师的解释对我来说太抽象了,我不知道是否有人能解释得更清楚

我想知道是否有人能简单地解释一下EDSL的组成部分,以及它们的特征。在我们的课程中,我们经历了DSL的浅层和深层嵌入,并研究了DSL的以下构建块:

  • 构造函数
  • 组合子(原语和派生)
  • 运行函数
  • 我认为constructor和run函数更具自解释性,因此我更感兴趣的是理解是什么使组合子派生或原语。如果有人解释其他的概念,那也没什么坏处。这是我们讲座中的一个例子供参考。它是DSL的一个浅层实现,用于创建信号:

    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))
    

    基本组合器是DSL中内置的组合器,用基本语言(即Haskell)定义。DSL通常是围绕一种抽象类型构建的,这种类型的实现对最终用户来说是隐藏的。它完全不透明。该语言提供的基本组合器需要知道抽象是如何实际实现的

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

    这与Haskell中的基本类型非常相似。例如,您不能自己实现
    Int
    Int
    之类的操作。这些要求编译器内置的东西才能工作,因为数字是经过特殊处理的。另一方面,
    Bool
    不是原始的;你可以把它写成图书馆

    data Bool = True | False -- ... you can't do this for Int!
    
    DSL的“原语”和“派生”是相同的概念,只是编译器实际上是您的Haskell库

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

    $$
    这样的函数是基本函数,因为它依赖于知道
    信号
    时间->A
    。更改
    信号的表示形式时
    ,必须重写
    $
    。此外,您的库的用户不能自己实现
    $

    另一方面,
    mapS
    是一个派生操作,因为它可以完全根据您正在导出的其他内容编写。它不需要知道任何有关
    信号的特殊信息,甚至可以由库的某个用户编写。实现可能类似于:

    mapS f signal = constS f $$ signal
    
    请注意它如何使用
    常量
    $
    ,但从不打开
    信号
    。如何展开信号的知识完全隐藏在这两个函数中<代码>映射
    是“派生”的,因为它只在DSL中编写,不需要任何低于抽象级别的东西。当您更改
    信号
    的实现时,
    映射
    仍将按原样工作:您只需正确更新
    常量
    $$
    即可免费获得
    映射


    所以:原语组合词是直接构建到您的语言中的,需要了解其内部实现细节的组合词。派生组合符完全是根据您的语言编写的,不依赖于这些内部细节。它们只是方便的函数,您的库的最终用户也可以很容易地编写它们。

    很好的解释。谢谢