这段模糊的Haskell代码是如何工作的?
在阅读(并忽略所有“冒犯性”内容)时,我偶然发现了以下一段模糊代码:这段模糊的Haskell代码是如何工作的?,haskell,Haskell,在阅读(并忽略所有“冒犯性”内容)时,我偶然发现了以下一段模糊代码: fix$(<$>)<$>(:)<*>((<$>((:[{- thor's mother -}])<$>))(=<<)<$>(*)<$>(*2))$1 fix$()(:)(((:[{thor's mother-}]))(=首先,我们有一个可爱的定义 x = 1 : map (2*) x 如果你以前从未见过它,那么它本身就有点令人费
fix$(<$>)<$>(:)<*>((<$>((:[{- thor's mother -}])<$>))(=<<)<$>(*)<$>(*2))$1
fix$()(:)(((:[{thor's mother-}]))(=首先,我们有一个可爱的定义
x = 1 : map (2*) x
如果你以前从未见过它,那么它本身就有点令人费解。无论如何,这是懒惰和递归的一个相当标准的技巧。现在,我们将使用fix
,和point-free来摆脱显式递归
x = fix (\vs -> 1 : map (2*) vs)
x = fix ((1:) . map (2*))
接下来我们要做的是扩展:
部分,并使映射变得不必要的复杂
x = fix ((:) 1 . (map . (*) . (*2)) 1)
好的,现在我们有两个常量1
。这永远不会发生,所以我们将使用reader应用程序来消除重复。另外,函数组合有点垃圾,所以让我们尽可能用()
替换它
x = fix (liftA2 (.) (:) (map . (*) . (*2)) 1)
x = fix (((.) <$> (:) <*> (map . (*) . (*2))) 1)
x = fix (((<$>) <$> (:) <*> (map <$> (*) <$> (*2))) 1)
我们可以将()
替换为()
,然后添加一些伪节:
map = (=<<) . ((:[]) <$>)
map = (=<<) <$> ((:[]) <$>)
map = (<$> ((:[]) <$>)) (=<<)
map=(=写了一个很长的答案,完整地浏览了我的IRC实验日志,直到最终的代码(这是在2008年初),但我无意中看到了所有的文本:)虽然没有那么大的损失——丹尼尔的分析大部分是正确的
我从这里开始:
Jan 25 23:47:23 <olsner> @pl let q = 2 : map (2*) q in q
Jan 25 23:47:23 <lambdabot> fix ((2 :) . map (2 *))
这两个答案都是从原来的短代码中派生出模糊代码片段,但问题实际上是问长的模糊代码是如何工作的
以下是方法:
fix$(<$>)<$>(:)<*>((<$>((:[{- thor's mother -}])<$>))(=<<)<$>(*)<$>(*2))$1
= {- add spaces, remove comment -}
fix $ (<$>) <$> (:) <*> ( (<$> ((:[]) <$>) ) (=<<) <$> (*) <$> (*2) ) $ 1
-- \__\______________/_____________________________/
= {- A <$> B <*> C $ x = A (B x) (C x) -}
fix $ (<$>) (1 :) ( ( (<$> ((:[]) <$>) ) (=<<) <$> (*) <$> (*2) ) 1 )
-- \__\______________/____________________________/
= {- op f g = (f `op` g) ; (`op` g) f = (f `op` g) -}
fix $ (1 :) <$> ( (((=<<) <$> ((:[]) <$>) ) <$> (*) <$> (*2) ) 1 )
-- \\____________________/____________________________/
= {- <$> is left associative anyway -}
fix $ (1 :) <$> ( ( (=<<) <$> ((:[]) <$>) <$> (*) <$> (*2) ) 1 )
-- \__________________________________________________/
= {- A <$> foo = A . foo when foo is a function -}
fix $ (1 :) <$> ( ( (=<<) <$> ((:[]) <$>) . (*) . (*2) ) 1 )
-- \__________________________________________________/
= {- ((:[]) <$>) = (<$>) (:[]) = fmap (:[]) is a function -}
fix $ (1 :) <$> ( ( (=<<) . ((:[]) <$>) . (*) . (*2) ) 1 )
-- \__________________________________________________/
= {- (a . b . c . d) x = a (b (c (d x))) -}
fix $ (1 :) <$> (=<<) ( ((:[]) <$>) ( (*) ( (*2) 1 )))
= {- (`op` y) x = (x `op` y) -}
fix $ (1 :) <$> (=<<) ( ((:[]) <$>) ( (*) 2 ))
= {- op x = (x `op`) -}
fix $ (1 :) <$> (=<<) ( ((:[]) <$>) (2*) )
= {- (f `op`) g = (f `op` g) -}
fix $ (1 :) <$> (=<<) ( (:[]) <$> (2*) )
= {- A <$> foo = A . foo when foo is a function -}
fix $ (1 :) <$> (=<<) ( (:[]) . (2*) )
= {- (f . g) = (\ x -> f (g x)) -}
fix $ (1 :) <$> (=<<) (\ x -> [2*x] )
= {- op f = (f `op`) -}
fix $ (1 :) <$> ( (\ x -> [2*x] ) =<<)
通过类型应用和替换,我们可以看到所讨论的monad是[]
,其中(>>=g)=concatMap g
concatMap(\x->[2*x])xs
简化为
concat $ map (\ x -> [2*x])
=
concat $ [ [2*x] | x <- xs]
=
[ 2*x | x <- xs]
=
map (\ x -> 2*x )
所以
((2*)^n) 1 = ((2*) . (2*) . ... . (2*)) 1
= 2* ( 2* ( ... ( 2* 1 )...))
= 2^n , for n in [0..]
我想知道答案是否是傲慢的冒犯……如果是真的,考虑到你努力避免粗俗,这是一种讽刺。你尝试过什么?最明显的尝试是:(a)删除注释,(b)重新格式化/删除代码,(c)找出正在使用的Functor/Applicative/Monad实例(可能全部列出,但不要假设……没有什么能阻止一个足够疯狂的程序员在一行代码中使用五个不同的Monad实例),(d)尽可能简化。然后看看剩下的是什么。Haskell是我最喜欢的编程语言,到目前为止,但还是让我笑了这么多!问题链接到。当有人在语言XYZ中找到了他们能找到的最神秘的代码片段,然后声称它是事实时,我真的很恼火“用XYZ语言编写可读代码几乎是不可能的”。但那只是我……第一段中省略“已删除”一词是故意的吗?如果是这样,我向你致敬,先生。@JakeBrownson这是一个,但我也不确定这是否是故意的。你遗漏了{-thor的母亲-}
!
fix$(<$>)<$>(:)<*>((<$>((:[{- Jörð -}])<$>))(=<<)<$>(*)<$>(>>=)(+)($))$1
fix$(<$>)<$>(:)<*>((<$>((:[{- thor's mother -}])<$>))(=<<)<$>(*)<$>(*2))$1
= {- add spaces, remove comment -}
fix $ (<$>) <$> (:) <*> ( (<$> ((:[]) <$>) ) (=<<) <$> (*) <$> (*2) ) $ 1
-- \__\______________/_____________________________/
= {- A <$> B <*> C $ x = A (B x) (C x) -}
fix $ (<$>) (1 :) ( ( (<$> ((:[]) <$>) ) (=<<) <$> (*) <$> (*2) ) 1 )
-- \__\______________/____________________________/
= {- op f g = (f `op` g) ; (`op` g) f = (f `op` g) -}
fix $ (1 :) <$> ( (((=<<) <$> ((:[]) <$>) ) <$> (*) <$> (*2) ) 1 )
-- \\____________________/____________________________/
= {- <$> is left associative anyway -}
fix $ (1 :) <$> ( ( (=<<) <$> ((:[]) <$>) <$> (*) <$> (*2) ) 1 )
-- \__________________________________________________/
= {- A <$> foo = A . foo when foo is a function -}
fix $ (1 :) <$> ( ( (=<<) <$> ((:[]) <$>) . (*) . (*2) ) 1 )
-- \__________________________________________________/
= {- ((:[]) <$>) = (<$>) (:[]) = fmap (:[]) is a function -}
fix $ (1 :) <$> ( ( (=<<) . ((:[]) <$>) . (*) . (*2) ) 1 )
-- \__________________________________________________/
= {- (a . b . c . d) x = a (b (c (d x))) -}
fix $ (1 :) <$> (=<<) ( ((:[]) <$>) ( (*) ( (*2) 1 )))
= {- (`op` y) x = (x `op` y) -}
fix $ (1 :) <$> (=<<) ( ((:[]) <$>) ( (*) 2 ))
= {- op x = (x `op`) -}
fix $ (1 :) <$> (=<<) ( ((:[]) <$>) (2*) )
= {- (f `op`) g = (f `op` g) -}
fix $ (1 :) <$> (=<<) ( (:[]) <$> (2*) )
= {- A <$> foo = A . foo when foo is a function -}
fix $ (1 :) <$> (=<<) ( (:[]) . (2*) )
= {- (f . g) = (\ x -> f (g x)) -}
fix $ (1 :) <$> (=<<) (\ x -> [2*x] )
= {- op f = (f `op`) -}
fix $ (1 :) <$> ( (\ x -> [2*x] ) =<<)
=
fix $ (1 :) . map (2*)
= {- substitute the definition of fix -}
let xs = (1 :) . map (2*) $ xs in xs
=
let xs = 1 : [ 2*x | x <- xs] in xs
= {- xs = 1 : ys -}
let ys = [ 2*x | x <- 1:ys] in 1:ys
= {- ys = 2 : zs -}
let zs = [ 2*x | x <- 2:zs] in 1:2:zs
= {- zs = 4 : ws -}
let ws = [ 2*x | x <- 4:ws] in 1:2:4:ws
=
iterate (2*) 1
=
[2^n | n <- [0..]]
(>>=) :: Monad m => m a -> (a -> m b ) -> m b
(\ x -> [2*x]) :: Num t => t -> [ t]
(>>= (\ x -> [2*x])) :: Num t => [ t] -> [ t]
concat $ map (\ x -> [2*x])
=
concat $ [ [2*x] | x <- xs]
=
[ 2*x | x <- xs]
=
map (\ x -> 2*x )
(f . g) x = f (g x)
fix f = let x = f x in x
iterate f x = x : iterate f (f x)
= x : let y = f x in
y : iterate f (f y)
= x : let y = f x in
y : let z = f y in
z : iterate f (f z)
= ...
= [ (f^n) x | n <- [0..]]
f^n = f . f . ... . f
-- \_____n_times _______/
((2*)^n) 1 = ((2*) . (2*) . ... . (2*)) 1
= 2* ( 2* ( ... ( 2* 1 )...))
= 2^n , for n in [0..]