Clojure China

04-10 Haskell 群讨论整理

#1

张未晨 11:50 monad设计出来,不是为了干什么,没有monad,maybe还是maybe,io还是io,大家都该干嘛干嘛,弄个monad只是为了给有类似行为的东西起个统称的名字而已。。。跟你把飞机和鸟抽象出一个接口叫flyable没有任何区别,怎么就装逼了

宰相小白板 11:51 我看haskell最初的目的是为了monad。看monad是为了用vert.x里面的一个monad实现,用那个monad实现是为了不想callback hell 。我离各位大神还差太远了。现在刚刚学到functor,monad还没有理解。

王旭林 11:51 @张未晨 是的。它不过是种抽象,抽象的还特别好

风哥 11:56 编程这种事情,只要认识ABC都可以去做,只是看你有没有兴趣

风哥 11:57 这话也不是我讲的,很多年前听一个很老的学者说的

风哥 11:58 早期的那些黑客都是一些小孩子,

风哥 12:00 很多人觉得编程是高科技是一种误解

风哥 12:01 所以就觉得小孩子编程很神,其实并不是,很多技艺都是从小学习的,为什绘画、体育、舞蹈都从小孩子学,编程为什么不呢

风哥 12:05 外行一般都会觉得这个好复杂,好难,编程确实很难很复杂,但并不妨碍你去学习,你让我去拉小提琴我也没办法,但是小孩子可以拉得很好

风哥 12:05 我也不会觉得自卑

风哥 12:06 谦虚,不从存在的,这辈子都不可能谦虚

风哥 12:12 我读哲学的,像是哲学家里面天才多了去了,克里普克高中就完成了博士论文,Quine 24岁哈佛博士毕业

工业聚-古映杰 14:06 问个问题 minimum >>= delete 这种写法,怎么理解?

工业聚-古映杰 14:06 >>= 的签名是 m a -> (a -> m b) -> m bminimumdelete 都是函数

工业聚-古映杰 14:07 把上述写法,换成等价的 do block 是这样的吗?

工业聚-古映杰 14:07

王旭林 14:09 mininum :: M a delete :: a -> Mb

风哥 14:09 不需要 return

风哥 14:10

风哥 14:10 do>>= 的翻译

王旭林 14:12

工业聚-古映杰 14:13 这样 GHC 会报错

余乐 14:13

工业聚-古映杰 14:13

风哥 14:14 那就不需要do

王旭林 14:14 你是怎么定义 Monad的instance的?@工业聚

风哥 14:14 []本身也是Monad

工业聚-古映杰 14:14 用 do 是为了尝试等价表达 minimum >>= delete

王旭林 14:14 是的,[] 本身是Monad的

工业聚-古映杰 14:15 delete (minimum xs) xs 是正常写法

王旭林 14:15 但 minimun >> delete 就得把 [a] -> a 定义为 Monad 才行啊?

工业聚-古映杰 14:15 minimum 不满足 m adelete 不满足 a -> m b,但可以 >>= 组合起来,并且不需要声明 instance

张未晨 14:15 minimum 又不返回 [a]

工业聚-古映杰 14:15

工业聚-古映杰 14:16 这个是全部代码~

风哥 14:16 搞这么复杂干吗 张未晨 14:17 操作list而已,你们确定一定要在do块里做么?

工业聚-古映杰 14:17

工业聚-古映杰 14:17 提问的目的,只是想理解 >>= 怎么把两个函数给整合起来

工业聚-古映杰 14:17 对于解决 removeSmallest 的问题,delete (minimum xs) xs 已经足够

风哥 14:18 函数类型也是 monad

风哥 14:18 这单参数的函数就是 monad 张未晨 14:19 对,这里的 m-> 不是 []

余乐 14:20 这个我也猜到了,就是这个 monad instance 是怎么定义的。

余乐 14:20 难道是 ->?

风哥 14:20 源码里面有

风哥 14:21 (->) a

风哥 14:25

王旭林 14:28 @Novalis 是的。这家伙好难认啊

王旭林 14:28 得练练才好认出来

王旭林 14:29 minimun :: Ord a => [a] -> a 属于 (v -> ?) 这个Monad

王旭林 14:30 delete :: Eq a => a -> [a] -> [a] 也可理解为 delete :: Eq a => a -> ([a] -> [a])

风哥 14:30 其实 m a 就是结果为 a 的计算 , (->) a 也是一样的理解

风哥 14:31 ((+1) >>= \x -> return x) 1 你看看这个算出来时多少,你就明白了

王旭林 14:32 delete :: Eq a => a -> ([a] -> [a]) 中的 ([a] -> [a]) 属于 (v -> ? ) 这个 Monad 所以 delete 的声明 可以为: delete :: Eq a => a -> M a

王旭林 14:32 这样就符合 (>>=) :: M a -> (a -> M b) 这个了

风哥 14:32 跟他那个 minmum 一样的道理

风哥 14:33 就相当于 (minmum >>= delete) 这整个是一个函数

风哥 14:33 你把 monad 当成一个黑盒,不管他的,但是你知道它需要一个参数,然后计算出一个结果

风哥 14:34 所以传入参数,(minmum >>= delete) [1,2,3]

风哥 14:34 同理你可以把任何这样的函数组合起来组成一个大的黑盒

王旭林 14:35 再说一下细的 minimun :: [a] -> a 相当于 (a -> ?) 这一个Monad 也就是可以写为 minimun :: M a delete:: a -> ([a] -> [a]) 相当于 a -> M b 这样 正好符合了: (>>=) :: M a -> (a -> M b) 所以 minimun >>= delete 是合法滴

NullPointerException 14:35 我是把monad看做一个管道,里面是impure的东西 外面是pure的东西…

风哥 14:35 ((+1) >>= (+) >>= (+)) 1

风哥 14:35 你看看这个多好玩,计算结果是多少

风哥 14:36 moand 就可以让你组合这些不同的计算

工业聚-古映杰 14:36

工业聚-古映杰 14:36 我尝试实现了一个 fake >>=

工业聚-古映杰 14:36 这下理解了

风哥 14:36 肯定可以啊

王旭林 14:36 Monad 是种抽象数据结构,看成管道就看扁Monad了

风哥 14:37 只要是单参数的函数都可以

工业聚-古映杰 14:37

夜色残阳 14:37 monad 主要看 >>= 的实现吧,也不是什么黑盒,>>= 不一样,计算传递的方式就不一样,所以才有state/reader/…,所以要理解不同的monad就去看他的定义就好了,而不是在这里猜来猜去

风哥 14:37 其实对于[a]也是一个计算嘛,结果是a的计算,至于[]是啥你不管他的,这就叫抽象

风哥 14:39 任何monad都是这样

风哥 14:39 这不是猜测,这就是monad的本质

风哥 14:40 你只有忽略这些细节你才能从抽象的角度把握monad

风哥 14:41 你掉进细节就上丧失了它的优势

风哥 14:41 就像OO编程讲究接口,都是有意识的做出抽象

风哥 14:42 你的moand的组合就不依赖于具体的实现,你只要保证类型是正确的就可以了

… 14:43 不然你老是去纠结不同 >>= 的实现细节 你一天也写不了多少hs代码

风哥 14:43 写haskell你想得越少就越符合直觉

风哥 14:44 Monad is nothing,这就对了

夜色残阳 14:44 类型正确,只能保证代码能跑起来,不能保证代码一定按我们想法跑起来,不然写Haskell也不用写测试了

风哥 14:45 monad一经证明就不用再去怀疑,逻辑错误往往和monad没啥关系

风哥 14:45 只是你组合的姿势对不对,monad本身还是应该看做黑盒

风哥 14:48 这也是体现了monad的封装性质

风哥 14:50 抽象肯定是有代价的

夜色残阳 14:53 首先要习惯这层抽象,习惯了就好,看见对应的monad,就知道大概是在做什么了,自己要用的时候也一样 :joy:

余乐

Zete 15:00 习题: ((+1) >>= (+) >>= (\x y z -> x + y + z)) 2 3 等于多少, 为什么 [呲牙]

风哥 15:02 fixed = cos 1 : map cos fixed haskell最大价值就是美学上的,可以写这么漂亮的代码,再慢有什么关系呢

风哥 15:02 其实比Python什么的还是快很多

Zete 15:52 其实 Python 也不差的 mpmath.findroot(lambda x: cos(x) - x, 1.0)

风哥 15:55 能无限取值吗

风哥 15:55 还是丑

Zete 16:35 Ruby 的思路: number.match?(/\A\d{13,16}\z/) and (*ns, checksum = number.chars.map &:to_i; ns.each_slice(2).flat_map{|n1, n2| (n1 * 2).divmod(10) << (n2 or 0) }.sum * 9 % 10 == checksum)

そら 17:09 只学过Haskell而且只学了一点表示完全看不懂[捂脸]