为什么 haskell 的 `fix` 似乎对元组有问题?
Why does haskell's `fix` seem to have trouble with tuples?
我正在努力研究定点和递归定义。
这个有效:
>>> take 10 $ let x = (0:x) in x
[0,0,0,0,0,0,0,0,0,0]
这做同样的事情,考虑到 fix
:
的定义,这是有道理的
>>> take 10 $ fix (\x -> (0:x))
[0,0,0,0,0,0,0,0,0,0]
现在假设我开始摆弄递归定义的对:
>>> take 10 $ fst $ let (u,v) = (0:v,1:u) in (u,v)
[0,1,0,1,0,1,0,1,0,1]
好吧,我应该也可以用 fix
来写吧?
>>> take 10 $ fst $ fix (\(u,v) -> (0:v,1:u))
*** Exception: <<loop>>
但是没用。除非我做以下看似微不足道的改变:
>>> take 10 $ fst $ fix (\r -> let (u,v)=r in (0:v,1:u))
[0,1,0,1,0,1,0,1,0,1]
最后两个示例之间的关键区别是什么?
你想要
take 10 $ fst $ fix (\ ~(u,v) -> (0:v,1:u))
^^^
从而使模式匹配变得懒惰。在 let
中,LHS 模式隐式为 lazy/irrefutable.
对于普通的 \(u,v) -> ...
,在生成任何输出之前将需要 lambda 的参数——这使得函数对于 fix
来说过于严格。你需要的是
take 10 $ fst $ fix (\p -> (0:snd p,1:fst p))
这样参数就不会被 lambda 强制执行(那里没有匹配的构造函数)。惰性模式方法等同于上面的fst/snd
。
我正在努力研究定点和递归定义。
这个有效:
>>> take 10 $ let x = (0:x) in x
[0,0,0,0,0,0,0,0,0,0]
这做同样的事情,考虑到 fix
:
>>> take 10 $ fix (\x -> (0:x))
[0,0,0,0,0,0,0,0,0,0]
现在假设我开始摆弄递归定义的对:
>>> take 10 $ fst $ let (u,v) = (0:v,1:u) in (u,v)
[0,1,0,1,0,1,0,1,0,1]
好吧,我应该也可以用 fix
来写吧?
>>> take 10 $ fst $ fix (\(u,v) -> (0:v,1:u))
*** Exception: <<loop>>
但是没用。除非我做以下看似微不足道的改变:
>>> take 10 $ fst $ fix (\r -> let (u,v)=r in (0:v,1:u))
[0,1,0,1,0,1,0,1,0,1]
最后两个示例之间的关键区别是什么?
你想要
take 10 $ fst $ fix (\ ~(u,v) -> (0:v,1:u))
^^^
从而使模式匹配变得懒惰。在 let
中,LHS 模式隐式为 lazy/irrefutable.
对于普通的 \(u,v) -> ...
,在生成任何输出之前将需要 lambda 的参数——这使得函数对于 fix
来说过于严格。你需要的是
take 10 $ fst $ fix (\p -> (0:snd p,1:fst p))
这样参数就不会被 lambda 强制执行(那里没有匹配的构造函数)。惰性模式方法等同于上面的fst/snd
。