Seija
首页
Travellings
登录
注册
首页
文章
由Haskell和面向对象引出的关于抽象的思考
### 为什么函数式比面向对象能进行更好的抽象 函数式的抽象粒度是函数而面向对象的抽象粒度是函数. 造成面向对象语言无法进行函数粒度的抽象是由面向对象语言的的
`副作用`
,`无柯里化` `无高级函数功能`等原因导致的. 其中最主要的原因就是副作用.举个例子. ```C# class ClassA { private int filedA; public int FuncA(int arg) { this.filedA += arg; return this.filedA; } } ``` 因为FuncA的副作用,他的作用域是完全局限于ClassA中的.只有ClassA是参与抽象的单元. 这里可以对比一下Haskell里的Reader Monad ```Haskell Render Int Int funcA::Int -> Reader Int Int funcA arg = do filedA <- ask return $ filedA + arg ``` 这里的funcA函数是适用于所有Reader Int Int 的情况的. ### 关于接口或者说类型类 接口是关于数据类型抽象的手段,它是**不易得的**,**是非廉价**的.错误的接口会事倍功半. 当我们开发一个没有经验的系统时,我们总喜欢先定义接口.但是这是不合理的. **人脑有一个很神奇的特性,我们总是对我们知之甚少的领域,胸有成竹** 关于我们要解决的这个问题领域,最适合他的接口,或者说他的脉络,我们是很难一次蒙对的. 这个时候我们应该采取两种办法. 1. 先定义出**最贴合你问题的数据结构**,然后再在这个基础上进行接口抽象 2. 参考你这个领域经验最丰富的代码,分析他们的大体脉络在进行抽象. ### 关于数据的组合 先来比对一下两种代码 ```haskell data Unit a = {pos::Vec2,uid::Text,val::a } data PairUnit a b= { pos::Vec2,uid::Text, valA:a ,valB:b } data Either a b = Left a | Right b ``` ```C# class Unit { protected Vec2 pos; protected Int64 uid; } class SubUnit : Unit { } class GUnit
{ protected Vec2 pos; protected Int64 uid; } class PairUnit
{ protected Vec2 pos; protected Int64 uid; valA:TA; valB:TB; } ``` 我们可以发现C#有两种数据组合的方式`继承`和`泛型`。 * 继承可以实现haskell中单类型参数的数据组合。 * 泛型可以实现haskell中多类型参数的组合 * C#中没有办法实现haskell中数据的`或`关系 但是`继承`和`泛型`都是有局限性的。 继承的缺点很明显,他只能组合单个元素。 ```c# class Unit {} class Sprite : Unit{} class Hero :Sprite {} ``` 等价于 ```haskell Unit (Sprite Hero) ``` 在Haskell中类型是`Unit (Sprite Hero)`而在c#中类型却是`Hero`。 #### 关于继承 c#其实在数据组合的同时耦合了类型的抽象。我们从接口的角度思考一下 c#在定义`Unit`和`Sprite`数据结构的时候同时定义了`IUnit`和`ISprite`。当继承的时候默认给他们实现了父类的接口。其实这是一种耦合的抽象。什么时候需要接口是我说了算的。`Unit (Sprite Hero)`这个数据要实现什么接口是需要我思考的。`IUnit`和`ISprite`这两个接口的定义非必须的。 #### 关于泛型 泛型虽然能进行多类型参数的数据组合。但是他有一个致命问题他是无法进行接口的实现的。例如说`GUnit
` `GUnit
`,只能给GUnit实现接口而无法给`GUnit
`和`GUnit
`单独实现接口。 ### 没有银弹 函数式编程只不过是把我们的思考角度从类移到了函数. 我们要承载更高的心智负担,才能写出更抽象的代码. 领域内问题的复杂度是不变的. 并不是说你使用了函数式语言你就不需要对领域内问题进行分析了. 我们应该始终秉承着`问题为核心`的思路. 将核心问题之外的`语言,语法,上下文环境`等噪音降为0.
SB Java程序员的代码可能只有30%的在解决实际问题,另外70%在脱了裤子出门打个酱油回家坐下再回去把忘拿的零钱拿到手然后回家蹲到马桶上顺时针旋转90度逆时针旋转89.5度然后以不大不小的力度按下抽水按钮然后微微抬起屁股对准马桶中心的斜上方放个屁 (虽然他只是想放个屁而已.
登录
登录
注册
最热文章
引擎中Template DSL的设计思考总结
10-19
ReaderT 设计模式
04-23
非主流引擎开发不出来 (n+1) : purescript侧结构设计
04-04
FRP系统的设计
03-17
非主流引擎开发不出来 (1) : 轻骨架
02-11
非主流引擎开发不出来 (0) : 引擎定位
12-09
Rust的ECS库specs
11-20
Haskell类型类高级扩展详细说明
05-31
CMake 速览
05-29
尼采导读:超人与永恒轮回
02-24
为什么elm的结构并不是最合理的?
02-20
React速览
02-20
尼采命运之爱
02-18
AspNetCore 速览
02-17
由Haskell和面向对象引出的关于抽象的思考
12-26
二进制文件压缩工具upx
12-24
Reflex介绍
12-17
Web的前端渲染和WebApi
12-16
前端FRP框架深度踩坑
12-16
Yesod - RESTful (11)
12-16
链接
github
gitee