【发布时间】:2015-07-11 16:33:08
【问题描述】:
假设我们有三个对象:
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
}
...
}
FirstObj 和 SecondObj 从 MainObj 继承 someProp 和 toggleSomeProp 并使用自己的属性和方法对其进行扩展。 SecondObj 扩展了 MainObj 的 state 属性(和 get/set 方法),可以是任何东西。
假设我们有两个对象FirstObjSrc 和SecondObjSrc,它们都有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
所以,我对这段代码有一些疑问:
- 这个实现是否正确?
-
ObjEff效果是否需要幻像类型s? - 如果有(或没有),那么我想了解原因(我已经阅读了https://wiki.haskell.org/Phantom_type 和其他一些的解释,我认为我了解基础知识,但效果让我感到困惑小)。
更新
假设上面的代码是某种虚构的浏览器(或 NodeJS)API,所以无法以某种方式更改它。
【问题讨论】:
-
函数式编程的基石之一是拥有不可变的数据结构并将任何可变状态保持在最低限度。不要有可变数据结构,让您的切换函数将旧数据结构作为参数,并返回包含新值的新数据结构。
-
@Bzzt 这个问题不是关于
toggleSomeProp,而是关于state。toggleSomeProp只是一个可以用...代替的噪音。上面的代码是浏览器原生代码的简化版本,所以实际上我无法让我的切换函数将旧数据结构作为参数。Event和CustomEvent可能是很好的例子。 -
我会检查像 purescript-simple-dom 这样的库,看看他们是如何做到的。对于不同的方法,purescript-halogen 使用 virtual-dom。
-
@Bzzt
Virtual-dom是关于渲染,而不是关于事件监听。而purescript-simple-dom不支持自定义事件。实际上,由于removeEventListener的实现方式,我对这个库有点怀疑。
标签: functional-programming purescript