效果和幻像类型

时间:2015-07-11 16:33:09

标签: functional-programming purescript

我们说我们有三个对象:

MainObj {
  someProp: false
  toggleSomeProp: function () {
    if (this.someProp)
      this.someProp = false
    else
      this.someProp = true
  }
  ...
}

FirstObj {
  someOtherProp: ...
  doSomethingWithOtherProp: function () {...}
  ...
}

SecondObj {
  state: null
  setState: function (s) {
    this.state = s
  }
  getState: function() {
    return this.state
  }
  ...
}

FirstObjSecondObjsomeProp继承toggleSomePropMainObj,并使用自己的属性和方法对其进行扩展。 SecondObj使用state属性(和get / set方法)扩展MainObj,可以是任何内容。

我们还说我们有两个FirstObjSrcSecondObjSrc对象都有getObj方法。第一个返回FirstObj,第二个返回SecondObj

这就是我在Purescript中实现的方式:

foreign import data ObjEff :: * -> !
foreign import data Obj :: *
foreign import data FirstObjSrc :: *
foreign import data SecondObjSrc :: *

foreign import somePropImpl :: forall a s e. a -> Eff (oe :: ObjEff s | e) Boolean
foreign import toggleSomePropImpl :: forall a s e. a -> Eff (oe :: ObjEff s | e) Unit

foreign import someOtherPropImpl :: ...
foreign import doSomethingWithOtherPropImpl :: ...

foreign import getStateImpl :: forall a b s e. (a -> Maybe a) -> Maybe a -> b -> Eff (oe :: ObjEff s | e) (Maybe s)
foreign import setStateImpl :: forall a s e. a -> s -> Eff (oe :: ObjEff s | e) Unit


foreign import getFirstObjImpl :: forall a s e. FirstObjSrc -> Eff (oe :: ObjEff s | e) a
foreign import getSecondObjImpl :: forall a s e. SecondObjSrc -> Eff (oe :: ObjEff s | e) a


class MainObj a where
  someProp :: forall s e. a -> Eff (oe :: ObjEff s | e) Boolean
  toggleSomeProp :: forall s e. a -> Eff (oe :: ObjEff s | e) Unit

class FirstObj a where
  someOtherProp :: ...
  doSomethingWithOtherProp :: ...

class (MainObj a) <= SecondObj a where
  getState :: forall s e. a -> Eff (oe :: ObjEff s | e) (Maybe s)
  setState :: forall s e. a -> s -> Eff (oe :: ObjEff s | e) Unit

class ObjSrc a where
  getObj :: forall b s e. a -> Eff (oe :: ObjEff s | e) b


instance objIsMainObj :: MainObj Obj where
  someProp = somePropImpl
  toggleSomeProp = toggleSomePropImpl

instance objIsFirstObj :: FirstObj Obj where
  someOtherProp = someOtherPropImpl
  doSomethingWithOtherProp = doSomethingWithOtherPropImpl

instance objIsSecondObj :: SecondObj Obj where
  getState = getStateImpl Just Nothing
  setState = setStateImpl

instance firstObjSrcIsObjSrc :: ObjSrc FirstObjSrc where
  getObj = getFirstObjImpl

instance secondObjSrcIsObjSrc :: ObjSrc SecondObjSrc where
  getObj = getSecondObjImpl

foreign import getFirstObjSrc :: forall s e. Eff (oe :: ObjEff s | e) FirstObjSrc
foreign import getSecondObjSrc :: forall s e. Eff (oe :: ObjEff s | e) SecondObjSrc

所以,我对这段代码有一些疑问:

  1. 此实施是否正确?
  2. ObjEff效果是否需要幻像类型s
  3. 如果确实(或没有),那么我想了解原因(我已经在https://wiki.haskell.org/Phantom_type和其他一些人阅读了解释,我认为我理解基础,但效果让我感到困惑。)
  4. 更新

    让我们说上面的代码是某种虚构的浏览器(或NodeJS)API,所以没有办法以某种方式改变它。

1 个答案:

答案 0 :(得分:0)

这个问题是基于比当前语言更旧且不兼容的版本。 Eff和效果行已被删除,而其位置为Effect(实际上,Eff没有效果行)。我猜想*已被Type取代,!已被删除(当我开始使用PureScript时,这些符号不存在)。

用于对象的符号有点混乱,因为它既不是JavaScript也不是我熟悉的任何其他标准符号。我的解释是,例如,

MainObj {
  someProp: false
  toggleSomeProp: function () {
    if (this.someProp)
      this.someProp = false
    else
      this.someProp = true
  }
  ...
}

表示此含义(在JavaScript中)

function MainObj() {
}
MainObj.prototype.someProp = false;
MainObj.prototype.toggleSomeProp = function () {
  if (this.someProp)
    this.someProp = false
  else
    this.someProp = true
}
// ...

在这种情况下,PureScript中可能的定义是:

foreign import data MainObj ∷ Type

foreign import someProp ∷ MainObj → Effect Boolean

foreign import toggleSomeProp ∷ MainObj → Effect Unit

实施文件为:

exports.someProp = function (mainObj) {
  return function () {
    return mainObj.someProp;
  };
};

exports.toggleSomeProp = function (mainObj) {
  return function () {
    return mainObj.toggleSomeProp();
  };
}

或者为了更好的内联和更容易的实现,这:

foreign import data MainObj ∷ Type

foreign import someProp ∷ EffectFn1 MainObj Boolean

foreign import toggleSomeProp ∷ EffectFn1 MainObj Unit

实现将是:

exports.someProp = function (mainObj) {
  return mainObj.someProp;
};

exports.toggleSomeProp = function (mainObj) {
  return mainObj.toggleSomeProp();
}

有多种方法可以做到(而且已经完成),但这是我几乎唯一使用的方法,因为它简单,明了且具有高度的适应性。

someProp必须有效导入,因为给定相同的对象它可以返回不同的结果。 toggleSomeProp必须有效导入,因为它以可观察的方式(通过someProp来改变状态)。