Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
509dfe2c97 | ||
|
|
806ee0177a | ||
|
|
fe4afdf89c |
@@ -813,25 +813,30 @@ function Parent() {
|
||||
换一个例子就可以看得更清楚:
|
||||
|
||||
```js
|
||||
function Parent() {
|
||||
function Parent(props) {
|
||||
const [count, setCount] = useState(0);
|
||||
const [step, setStep] = useState(0);
|
||||
const [other, setOther] = useState(0);
|
||||
const drag = useDraggable(count, step); // 封装了拖拽函数
|
||||
const drag = useDraggable(props.dom, count, step); // 封装了拖拽函数
|
||||
|
||||
useEffect(() => {
|
||||
// dom 变化时重新实例化
|
||||
drag()
|
||||
}, [drag])
|
||||
}
|
||||
```
|
||||
|
||||
假设我们使用 [Sortablejs](https://github.com/SortableJS/Sortable) 对某个区域进行拖拽监听,这个函数每次都重复执行的性能损耗非常大,**然而这个函数内部可能因为仅仅要上报一些日志,所以依赖了没有实际被使用的 `count` `step` 变量:**
|
||||
|
||||
```js
|
||||
function useDraggable(count, step) {
|
||||
function useDraggable(dom, count, step) {
|
||||
return useCallback(() => {
|
||||
// 上报日志
|
||||
report(count, step);
|
||||
|
||||
// 对区域进行初始化,非常耗时
|
||||
// ... 省略耗时代码
|
||||
}, [count, step]);
|
||||
}, [dom, count, step]);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,372 @@
|
||||
## 1 引言
|
||||
|
||||
Flex 与 Grid 相比就像功能键盘和触摸屏。触摸屏的控制力相比功能键盘来说就像是降维打击,因为功能键盘只能上下左右控制(x、y 轴),而触摸屏打破了布局障碍,直接从(z 轴)触达,这样 **无论 UI 内部布局再复杂,都可以通过 touch 直接定位。**
|
||||
|
||||
Flex 是一维布局方式,我们需要不断嵌套 Div 才能形成复杂结构,而一旦布局产生了变化,原有嵌套结构如果不能 “兼容变化” 到新结构,代码就需要重构。而 Grid 就像触摸屏一样,可以二维布局,即便布局方式做了翻天覆地的调整,也仅需少量修改就能适配。
|
||||
|
||||
这就是这次精读 [用 css grid 重新思考布局](https://www.freecodecamp.org/news/css-grid-changes-how-we-can-think-about-structuring-our-content/) 的原因,理解这个革命性布局技术给布局,甚至代码逻辑组织带来的变化。
|
||||
|
||||
## 2 概述
|
||||
|
||||
作者首先抛出了 Flex 的问题,其实是 `block` `float` `flex` 这三种布局模式的通病:
|
||||
|
||||
- 布局结构由 Div 层级结构描述,导致 Div 层级复杂且遇到结构变更时难以维护。
|
||||
- 定制能力弱。Flex 布局有一些不受控制的智能设定,比如宽度 50% 的子元素会被同级元素挤到 50% 以下,这种智能化在某些场景是需要的,但由于没有提供像 Grid 的 `minmax` 之类的 API,所以定制型不足。
|
||||
|
||||

|
||||
|
||||
举个例子,上图的结构用 Flex 描述可能是这样的:
|
||||
|
||||
```html
|
||||
<div class="card">
|
||||
<div class="profile-sidebar">
|
||||
<img src="https://i.pravatar.cc/125?image=3" alt="" class="profile-img" />
|
||||
<ul class="social-list">
|
||||
<li>
|
||||
<a href="#" class="social-link"
|
||||
><i class="fab fa-dribbble-square"></i
|
||||
></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="social-link"
|
||||
><i class="fab fa-facebook-square"></i
|
||||
></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="social-link"
|
||||
><i class="fab fa-twitter-square"></i
|
||||
></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="profile-body">
|
||||
<h2 class="profile-name">Ramsey Harper</h2>
|
||||
<p class="profile-position">Graphic Designer</p>
|
||||
<p class="profile-info">
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere a tempore,
|
||||
dignissimos odit accusantium repellat quidem, sit molestias dolorum
|
||||
placeat quas debitis ipsum esse rerum?
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
利用 HTML 嵌套结构,我们将图形纵向分成两大块,然后在每块内部继续嵌套划分布局,这是最经典的布局行为了。
|
||||
|
||||

|
||||
|
||||
样式文件里,我们需要对每层布局进行描述,同时支持多分辨率弹性布局,包括顶层 `card` 容器在内的一些样式需要做一定调整:
|
||||
|
||||
```scss
|
||||
.card {
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 600px;
|
||||
background: #005e9b;
|
||||
flex-basis: 250px;
|
||||
color: white;
|
||||
padding: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.profile-info {
|
||||
font-weight: 300;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.profile-sidebar {
|
||||
margin-right: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.profile-name {
|
||||
letter-spacing: 1px;
|
||||
font-size: 2rem;
|
||||
margin: 0.75em 0 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.profile-name::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 2em;
|
||||
height: 1px;
|
||||
background: #5bcbf0;
|
||||
margin: 0.5em auto 0.65em;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.profile-position {
|
||||
text-transform: uppercase;
|
||||
font-size: 0.875rem;
|
||||
letter-spacing: 3px;
|
||||
margin: 0 0 2em;
|
||||
line-height: 1;
|
||||
color: #5bcbf0;
|
||||
}
|
||||
|
||||
.profile-img {
|
||||
max-width: 100%;
|
||||
border-radius: 50%;
|
||||
border: 2px solid white;
|
||||
}
|
||||
|
||||
.social-list {
|
||||
list-style: none;
|
||||
justify-content: space-evenly;
|
||||
display: flex;
|
||||
min-width: 125px;
|
||||
max-width: 175px;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.social-link {
|
||||
color: #5bcbf0;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.social-link:hover,
|
||||
.social-link:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.bio {
|
||||
padding: 2em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media (min-width: 450px) {
|
||||
.bio {
|
||||
text-align: left;
|
||||
max-width: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
.bio-title {
|
||||
color: #0090d1;
|
||||
font-size: 1.25rem;
|
||||
letter-spacing: 1px;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.bio-body {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.profile {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
@media (min-width: 450px) {
|
||||
.card {
|
||||
flex-direction: row;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.profile-name::after {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
让我们看看 Grid 是怎么做的吧!Grid 有许多 API,我们重点看 `grid-template-areas` 这个属性,利用它,我们可以不关心模块的 HTML 结构,直接平铺方式描述:
|
||||
|
||||
```html
|
||||
<div class="card">
|
||||
<img src="https://i.pravatar.cc/125?image=3" alt="" class="profile-img" />
|
||||
<ul class="social-list">
|
||||
<li>
|
||||
<a href="#" class="social-link"><i class="fab fa-dribbble-square"></i></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="social-link"><i class="fab fa-facebook-square"></i></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="social-link"><i class="fab fa-twitter-square"></i></a>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 class="profile-name">Ramsey Harper</h2>
|
||||
<p class="profile-position">Graphic Designer</p>
|
||||
<p class="profile-info">
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere a tempore,
|
||||
dignissimos odit accusantium repellat quidem, sit molestias dolorum placeat
|
||||
quas debitis ipsum esse rerum?
|
||||
</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
可以看到,使用 Grid 可以将 UI 结构与 HTML 结构分离,HTML 结构仅描述包含关系,我们只需在样式文件中描述具体 UI 结构。
|
||||
|
||||
样式文件只截取 Grid 相关部分:
|
||||
|
||||
```scss
|
||||
.card {
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 600px;
|
||||
background: #005e9b;
|
||||
flex-basis: 250px;
|
||||
color: white;
|
||||
padding: 2em;
|
||||
text-align: left;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 3fr;
|
||||
grid-column-gap: 2em;
|
||||
grid-template-areas:
|
||||
"image name"
|
||||
"image position"
|
||||
"social description";
|
||||
}
|
||||
|
||||
.profile-name {
|
||||
grid-area: name;
|
||||
}
|
||||
.profile-position {
|
||||
grid-area: position;
|
||||
}
|
||||
.profile-info {
|
||||
grid-area: description;
|
||||
}
|
||||
.profile-img {
|
||||
grid-area: image;
|
||||
}
|
||||
.social-list {
|
||||
grid-area: social;
|
||||
}
|
||||
```
|
||||
|
||||
可以看到,`grid-template-areas` 是进一步抽象的语法,将页面结构通过直观的文本描述,无论是理解还是修改都更为轻松。
|
||||
|
||||
这种描述方式适配不同分辨率下也具有优势,只要重组 `grid-template-areas` 即可:
|
||||
|
||||
```scss
|
||||
@media (min-width: 600px) {
|
||||
.card {
|
||||
text-align: left;
|
||||
grid-template-columns: 1fr 3fr;
|
||||
grid-template-areas:
|
||||
"image name"
|
||||
"image position"
|
||||
"social description";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
归根结底,Grid 通过二维结构描述,将子元素布局控制收到了父级,使布局描述更加直观。
|
||||
|
||||
最后作者也提到,Flex 依然有使用场景,即简单的一维结构,或者 `space-between` 等 Flex 独有语法的情况。因此推荐整体、复杂的二维布局采用 Grid,一维的简单布局采用 Flex。
|
||||
|
||||
## 3 精读
|
||||
|
||||
Grid 的布局思路给了我很多启发,HTML 结构与 UI 结构的分离有助于减少 DIV 的层级结构,使代码看上去更清晰。
|
||||
|
||||
也许有人会疑惑,Grid 无非将 HTML 布局部分功能挪到了 CSS,整体复杂度应该不变。其实,从 `grid-template-areas` 这个 API 可以看到,Grid 不仅仅将布局功能抽到 CSS 中,更是将布局描述进行了一层抽象,使代码更易维护。
|
||||
|
||||
### 抽象,再抽象
|
||||
|
||||
为什么 Grid 可以对布局进行抽象?因为 Grid 将二维结构都掌握在手中,得到了更大的布局能力,才能进一步将结构化语法抽象为字符串的描述。
|
||||
|
||||
抽象的好处是不言而喻的,你觉得一堆嵌套的 DIV 与下面的代码,哪个更易读呢?
|
||||
|
||||
```scss
|
||||
.card {
|
||||
grid-template-areas:
|
||||
"image name"
|
||||
"image position"
|
||||
"social description";
|
||||
}
|
||||
```
|
||||
|
||||
这就是抽象的好处,一般来说,代码抽象程度越高就越易读,越易维护。
|
||||
|
||||
再看一个 Chrome Grid 插件,将 Grid 可视化显示出来,并可以以 UI 方式进行调整:
|
||||
|
||||

|
||||
|
||||
UI 是对文本的再抽象,同时可以规避一些不可能存在的语法,比如:
|
||||
|
||||
```scss
|
||||
.card {
|
||||
grid-template-areas:
|
||||
"image name"
|
||||
"image position"
|
||||
"social image";
|
||||
}
|
||||
```
|
||||
|
||||
布局只能以凸多边形方式拓展,不可能分离,也不可能突然插入一个其他模块而变成凹多边形。因此 UI 可以将这个错误规避,并简化为横竖多条线的方式对 UI 进行划分,显然这种描述方式效率更高。
|
||||
|
||||
不得不说,Grid 以及图形化插件的探索,是布局领域的一大进步,是不断抽象的尝试,要解决的问题只有一个:如何提供一种更直观的描述 UI 的方式。
|
||||
|
||||
### 布局对模块化的影响
|
||||
|
||||
Grid 将布局方式提高了一个维度,会直接影响到 JS 模块化方式。
|
||||
|
||||
尤其是以 JSX 组织代码的情况下,一个模块等于 UI + JS,通过嵌套方式的布局会让我们更倾向于站在 UI 视角划分模块。
|
||||
|
||||

|
||||
|
||||
比如对于上图模块,如果用 Flex 方式布局,我们可能会首先创建模块 X 作为左侧容器,子元素是 A 和 B,创建模块 Y 作为右侧容器,子元素是 C 以及新容器 Z,Z 容器的子元素是 D 和 E。
|
||||
|
||||
如果你的第一印象是这么组织代码,不得不承认模块化会受到布局方式的影响。虽然许多时候这样划分是正确的,但当这 5 个模块各自没有关联时,我们创建的容器 X、Y、Z 就失去了复用性,在新的组合场景我们又要重新组合一遍。
|
||||
|
||||
但是在 Grid 语法中,我们不需要 X、Y、Z,只需要用 [css grid generator](https://cssgrid-generator.netlify.com/) 按照上图的方式拖拖拽拽即可自动生成如下布局代码:
|
||||
|
||||
```scss
|
||||
.parent {
|
||||
display: grid;
|
||||
grid-template-columns: 3fr repeat(2, 1fr);
|
||||
grid-template-rows: repeat(5, 1fr);
|
||||
grid-column-gap: 0px;
|
||||
grid-row-gap: 0px;
|
||||
}
|
||||
|
||||
.div1 {
|
||||
grid-area: 1 / 1 / 3 / 2;
|
||||
}
|
||||
.div2 {
|
||||
grid-area: 3 / 1 / 6 / 2;
|
||||
}
|
||||
.div3 {
|
||||
grid-area: 1 / 2 / 2 / 4;
|
||||
}
|
||||
.div4 {
|
||||
grid-area: 2 / 2 / 6 / 3;
|
||||
}
|
||||
.div5 {
|
||||
grid-area: 2 / 3 / 6 / 4;
|
||||
}
|
||||
```
|
||||
|
||||
其实 `grid-template-columns` `grid-template-rows` 组合起来使用比 `grid-template-areas` 更强大,但是纯代码方式描述没有 `grid-template-areas` 直观,可是配合一些可视化系统就非常直观了:
|
||||
|
||||

|
||||
|
||||
将 A ~ E 这 5 个模块布局抽出来后,它们之间的关系就打平了,我们可以完全从逻辑视角审视如何做模块化了。
|
||||
|
||||
## 4 总结
|
||||
|
||||
CSS Grid 本质上是一种二维布局的语法,相比 [Block](https://www.w3schools.com/Css/css_inline-block.asp)、[Flex](https://www.w3schools.com/Css/css3_flexbox.asp) 等一维布局方案,多了一个维度可以同时从行与列角度定义布局,因此派生出 `grid-template-areas` 等语法,整体上更内聚更直观,抽象度也更高了。
|
||||
|
||||
理解了这些也就理解了布局未来的发展方向,**让布局与 Dom 分离** 一直是前端的一个梦想,开发 UI 部分时,只需关心页面由哪些模块组成,去实现这些模块就行了,而不需要关心模块之间应该如何组合。在描述组合时,可以通过可视化或比较抽象的字符串描述布局的结构,并对应到写好的模块上,这样的代码维护性远高于用 DIV 描述结构的方案。
|
||||
|
||||
> 讨论地址是:[精读《用 css grid 重新思考布局》 · Issue #211 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/211)
|
||||
|
||||
**如果你想参与讨论,请 [点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。**
|
||||
|
||||
> 关注 **前端精读微信公众号**
|
||||
|
||||
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">
|
||||
|
||||
> 版权声明:自由转载-非商用-非衍生-保持署名([创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh))
|
||||
@@ -0,0 +1,136 @@
|
||||
## 1 引言
|
||||
|
||||
函数式语言在深度学习领域应用很广泛,因为函数式与深度学习模型的契合度很高,[The Beauty of Functional Languages in Deep Learning — Clojure and Haskell](https://www.welcometothejungle.co/fr/articles/btc-deep-learning-clojure-haskell) 就很好的诠释了这个道理。
|
||||
|
||||
通过这篇文章可以加深我们对深度学习与函数式编程的理解。
|
||||
|
||||
## 2 概述与精读
|
||||
|
||||
深度学习是机器学习中基于人工神经网络模型的一个分支,通过模拟多层神经元的自编码神经网络,将特征逐步抽象化,这需要多维度、大数据量的输入。[TensorFlow](https://www.tensorflow.org/) 和 [PyTorch](https://pytorch.org/) 是比较著名的 Python 深度学习框架,同样 [Keras](https://blog.rstudio.com/2017/09/05/keras-for-r/) 在 R 语言中也很著名。然而在生产环境中,基于 **性能和安全性** 的考虑,一般会使用函数式语言 [Clojure](https://www.clojure.org/) 或 [Haskell](https://www.haskell.org/)。
|
||||
|
||||
在生产环境中,可能要并发出里几百万个参数,因此面临的挑战是:如何高效、安全的执行这些运算。
|
||||
|
||||
**所以为什么函数式编程语言可以胜任深度学习的计算要求呢?** 深度学习的计算模型本质上是数学模型,而数学模型本质上和函数式编程思路是一致的:数据不可变且函数间可以任意组合。这意味着使用函数式编程语言可以更好的表达深度学习的计算过程,因此更容易理解与维护,同时函数式语言内置的 Immutable 数据结构也保障了并发的安全性。
|
||||
|
||||
另外函数式语言的函数之间都是相互隔离的,即便在多线程环境下也不会发生竞争和死锁的情况,函数式编程语言会自动处理这些情况。
|
||||
|
||||
比如说 [Clojure](https://www.clojure.org/),**它甚至可在两个同时修改同一引用的程序并发运行时,自动重试其中之一,而不需要手动加锁**:
|
||||
|
||||
```clojure
|
||||
(import ‘(java.util.concurrent Executors))
|
||||
(defn test-stm [nitems nthreads niters]
|
||||
(let [refs (map ref (repeat nitems 0))
|
||||
pool (Executors/newFixedThreadPool nthreads)
|
||||
tasks (map (fn [t]
|
||||
(fn []
|
||||
(dotimes [n niters]
|
||||
(dosync
|
||||
(doseq [r refs]
|
||||
(alter r + 1 t))))))
|
||||
(range nthreads))]
|
||||
(doseq [future (.invokeAll pool tasks)]
|
||||
(.get future))
|
||||
(.shutdown pool)
|
||||
(map deref refs)))
|
||||
(test-stm 10 10 10000) -> (550000 550000 550000 550000 550000 550000 550000 550000 550000 550000)
|
||||
```
|
||||
|
||||
上面的代码创建了引用(refs),同时创建了多个线程自增这个引用对象,按理说每个线程都修改这个引用会导致竞争状态出现,但从结果来看是正常的,说明 Clojure 引擎在执行时会自动解决这个问题。实际上当两个线程出现竞争而失败时,Clojure 会自动重试其中之一。
|
||||
|
||||
> [原文介绍](https://clojure.org/about/concurrent_programming)
|
||||
|
||||
**Clojure 的另一个优势是并行效率高:**
|
||||
|
||||
```clojure
|
||||
(defn calculate-pixels-2 []
|
||||
(let [n (* *width* *height*)
|
||||
work (partition (/ n 16) (range 0 n))
|
||||
result (pmap (fn [x]
|
||||
(doall (map
|
||||
(fn [p]
|
||||
(let [row (rem p *width*) col (int (/ p *height*))]
|
||||
(get-color (process-pixel (/ row (double *width*)) (/ col (double *height*))))))
|
||||
x)))
|
||||
work)]
|
||||
(doall (apply concat result))))
|
||||
```
|
||||
|
||||
使用 `partition` 结合 `pmap` 可以使并发效率达到最大化,也就是 CPU 几乎都消耗在实际计算上,而不是并行的任务管理与上下文切换。Clojure 凭借 `partition` 对计算进行分区,采取分而治之并对分区计算结果进行合并的思路优化了并发性能。
|
||||
|
||||
> [原文介绍](http://www.fatvat.co.uk/2009/05/jvisualvm-and-clojure.html)
|
||||
|
||||
Clojure 另一个特性是函数链式调用:
|
||||
|
||||
```clojure
|
||||
;; pipe arg to function
|
||||
(-> "x" f1) ; "x1"
|
||||
|
||||
;; pipe. function chaining
|
||||
(-> "x" f1 f2) ; "x12"
|
||||
```
|
||||
|
||||
其中 `(-> "x" f1 f2)` 等价于 `f2(f1("x"))`,这种描述不仅更简洁清晰,也更接近于实际数学模型。
|
||||
|
||||
> [原文介绍](http://xahlee.info/clojure/clojure_function_chaining.html)
|
||||
|
||||
最后,Clojure 还具备计算安全性,计算过程不会修改已有的数据,因此在神经网络的任何一层的原始值都会保留,每层计算都可以独立运行且函数永远幂等。
|
||||
|
||||
[Haskell](https://www.haskell.org/) 也有独特的优势,**它具有类型推断、惰性求值等特性**,被认为更适合用于机器学习。
|
||||
|
||||
类型推断即 Haskell 类型都是静态的,如果试图赋予错误的类型会报错。
|
||||
|
||||
Haskell 的另一个优势是可以非常清晰的描述数学模型。
|
||||
|
||||
想想一般数学模型是怎么描述函数的:
|
||||
|
||||
```text
|
||||
fn =>
|
||||
f1 = 1
|
||||
f2 = 9
|
||||
f3 = 16
|
||||
n > 2, fn = 3fn-3 + 2fn-2 + fn-1
|
||||
```
|
||||
|
||||
一般语言用 `if-else` 描述等价关系,但 Haskell 可以几乎原汁原味的还原函数定义过程:
|
||||
|
||||
```haskell
|
||||
solve :: Int -> Interger
|
||||
solve 1 = 1
|
||||
solve 2 = 9
|
||||
solve 3 = 16
|
||||
solve n = 3 * solve (n - 3) + 2 * solve (n - 2) + solve (n - 1)
|
||||
```
|
||||
|
||||
这使得阅读 Haskell 代码和阅读数学公式一样轻松。
|
||||
|
||||
> [原文](https://blog.jle.im/entry/purely-functional-typed-models-1.html)
|
||||
|
||||
Haskell 另一个优势是惰性求值,即计算会在真正用到时才进行,而不会在计算前提前消费掉,比如:
|
||||
|
||||
```haskell
|
||||
let x = [1..]
|
||||
let y = [2,4 ..]
|
||||
head (tail tail( (zip x y)))
|
||||
```
|
||||
|
||||
可以看到,`x` 与 `y` 分别是 `1,2,3,4,5,6...` 与 `2,4,6,8...` 的无限数组,而 `zip` 函数将其整合为一个新数组 `(1,2),(2,4),(3,6),(4,8)...` 这也是无限数组,如果将 `zip` 函数执行完那么程序就会永远执行下去。但 Haskell 却不会陷入死循环,而是直接输出第一位数字 `1`。这就是惰性计算的特性,无论数组有多长,只有真正用到某项时才对其进行计算,所以哪怕初始数据量或计算量很大,实际消耗的运算资源只取决于这次计算实际用到的部分。
|
||||
|
||||
由于深度学习数据量巨大,惰性求值可以忽略海量数据输入,大大提升计算性能。
|
||||
|
||||
## 3 总结
|
||||
|
||||
本文介绍了为什么深度学习更适合使用函数式语言,以及介绍了 Clojure 与 Haskell 语言的共性:安全性、高性能,以及各自独有的特性,证明了为何这两种语言更适合用在深度学习中。
|
||||
|
||||
在前端领域说到函数式或函数之美,大部分时候想到的是 Class Component 与 Function Component 的关系,这个理解是较为片面的。通过本文我们可以了解到,函数式的思想与数学表达式思想如出一辙,以写数学公式的思维方式写代码,就是一种较好的函数式编程思路。
|
||||
|
||||
函数式应该只有表达式,没有语句,这是因为函数式是为了处理运算而诞生的,因此很适合用在深度学习领域。
|
||||
|
||||
> 讨论地址是:[精读《深度学习 - 函数式之美》 · Issue #212 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/212)
|
||||
|
||||
**如果你想参与讨论,请 [点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。**
|
||||
|
||||
> 关注 **前端精读微信公众号**
|
||||
|
||||
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">
|
||||
|
||||
> 版权声明:自由转载-非商用-非衍生-保持署名([创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh))
|
||||
Reference in New Issue
Block a user