【发布时间】:2015-05-19 08:04:42
【问题描述】:
我决定尝试函数式编程和 Purescript。在阅读了"Learn you a Haskell for great good" 和"PureScript by Example" 并稍微玩了一下代码之后,我认为我可以说我了解基础知识,但有一件事让我很困扰 - 代码看起来非常耦合。我通常会经常更改库,在 OOP 中我可以使用洋葱架构将我自己的代码与特定于库的代码分离,但我不知道如何在 Purescript 中执行此操作。
我试图找出人们在 Haskell 中是如何做到这一点的,但我只能找到诸如“没有人在 Haskell 中制作过复杂的应用程序,所以没有人知道如何做到这一点”或“你有输入和你有输出,中间的一切都只是纯函数”。但是现在我有一个玩具应用程序,它使用了虚拟 dom、信号、Web 存储、路由器库,它们每个都有自己的效果和数据结构,所以听起来不像一个输入和一个输出。
所以我的问题是我应该如何构建我的代码或我应该使用什么技术,这样我就可以在不重写我的应用程序的一半的情况下更改我的库?
更新:
在主模块中使用多层并保持效果的建议也很常见,我明白为什么要这样做。
这是一个简单的例子,希望能说明我正在谈论的问题:
btnHandler :: forall ev eff. (MouseEvent ev) => ev -> Eff (dom :: DOM, webStorage :: WebStorage, trace :: Trace | eff) Unit
btnHandler e = do
btn <- getTarget e
Just btnId <- getAttribute "id" btn
Right clicks <- (getItem localStorage btnId) >>= readNumber
let newClicks = clicks + 1
trace $ "Button #" ++ btnId ++ " has been clicked " ++ (show newClicks) ++ " times"
setText (show newClicks) btn
setItem localStorage btnId $ show newClicks
-- ... maybe some other actions
return unit
-- ... other handlers for different controllers
btnController :: forall e. Node -> _ -> Eff (dom :: DOM, webStorage :: WebStorage, trace :: Trace | e) Unit
btnController mainEl _ = do
delegateEventListener mainEl "click" "#btn1" btnHandler
delegateEventListener mainEl "click" "#btn2" btnHandler
delegateEventListener mainEl "click" "#btn3" btnHandler
-- ... render buttons
return unit
-- ... other controllers
main :: forall e. Eff (dom :: DOM, webStorage :: WebStorage, trace :: Trace, router :: Router | e) Unit
main = do
Just mainEl <- body >>= querySelector "#wrapper"
handleRoute "/" $ btnController mainEl
-- ... other routes each with it's own controller
return unit
这里我们有一个简单的计数器应用程序,其中包含路由、网络存储、dom 操作和控制台日志记录。如您所见,没有单一的输入和单一的输出。我们可以从路由器或事件监听器获取输入,并使用控制台或 dom 作为输出,所以它变得有点复杂。
在主模块中包含所有这些有效的代码对我来说感觉不对,原因有两个:
- 如果我继续添加路由和控制器,这个模块很快就会变成一千行混乱。
- 将路由、dom 操作和数据存储保持在同一个模块中违反了单一职责原则(我认为这在 FP 中也很重要)
我们可以将此模块拆分为多个模块,例如每个控制器一个模块并创建某种有效层。但是当我有十个控制器模块并且我想更改我的 dom 特定库时,我应该全部编辑它们。
这两种方法都远非理想,所以问题是我应该选择哪一种?或者也许还有其他方法可以走?
【问题讨论】:
标签: haskell architecture purescript