很抱歉问这个问题,但它看起来像是打破了参考透明度.
在探索问题并将其分解时(问题是获取列表列表的对角元素)我想出了这个(正确工作)解决方案:
import Data.List
nums = [[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16]]
southwest = transpose . zipWith (drop) [0..]
southwest2 = transpose . zipWith (drop) [0..] . transpose
my_ans = southwest nums ++ southwest2 nums
Run Code Online (Sandbox Code Playgroud)
(注意它包含两次中间行,这对我的用例来说不是问题)
现在很明显,很容易被重构.在第一次尝试以无点样式编写它之后,我认为通过这些尝试简单地编写它是非易点的:
my_ans2 x = (diagFunc x) ++ (diagFunc . transpose x)
where diagFunc = transpose . zipWith (drop) [0..]
my_ans3 x = concat [(diagFunc x), (diagFunc . transpose x)]
where diagFunc = transpose . zipWith (drop) [0..]
Run Code Online (Sandbox Code Playgroud)
现在这些编译和作品都不会让我感到困惑,因为在我看来,这会破坏参照透明度.有人可以解释为什么我错了,以及如何正确地编写这个函数(额外的点是以无点的方式编写它,因为我不能).
作为参考,错误在这里:
/home/michael/scripts/temp.hs:14:30:
Couldn't match expected type ‘[[a]]’
with actual type ‘a0 -> [[a1]]’
Relevant bindings include
x :: [[a]]
(bound at /home/michael/scripts/project_euler/temp.hs:14:9)
my_ans2 :: [[a]] -> [[a]]
(bound at /home/michael/scripts/project_euler/temp.hs:14:1)
In the second argument of ‘(++)’, namely ‘(diagFunc . transpose x)’
In the expression: (diagFunc x) ++ (diagFunc . transpose x)
In an equation for ‘my_ans2’:
my_ans2 x
= (diagFunc x) ++ (diagFunc . transpose x)
where
diagFunc = transpose . zipWith (drop) [0 .. ]
/home/michael/scripts/temp.hs:14:41:
Couldn't match expected type ‘a0 -> [[a1]]’
with actual type ‘[[a]]’
Relevant bindings include
x :: [[a]]
(bound at /home/michael/scripts/project_euler/temp.hs:14:9)
my_ans2 :: [[a]] -> [[a]]
(bound at /home/michael/scripts/project_euler/temp.hs:14:1)
Possible cause: ‘transpose’ is applied to too many arguments
In the second argument of ‘(.)’, namely ‘transpose x’
In the second argument of ‘(++)’, namely ‘(diagFunc . transpose x)’
Run Code Online (Sandbox Code Playgroud)
再一次,我非常肯定我错了,我只需要有人指出如何.:) 提前致谢.
你可以修复它:
my_ans2 x = (diagFunc x) ++ (diagFunc . transpose $ x)
where diagFunc = transpose . zipWith (drop) [0..]
my_ans3 x = concat [(diagFunc x), (diagFunc . transpose $ x)]
where diagFunc = transpose . zipWith (drop) [0..]
Run Code Online (Sandbox Code Playgroud)
问题是diagFunc . transpose x解析为diagFunc . (transpose x),而不是(diagFunc . transpose) x你想要的.
您可以使用函数的monoid实例以无点样式编写它:
import Data.Monoid
my_ans2' = diagFunc `mappend` (diagFunc . transpose)
where diagFunc = transpose . zipWith (drop) [0..]
Run Code Online (Sandbox Code Playgroud)
函数的monoid实例可用于返回monoidal值的函数.由于名单是幺那里mappend= (++)你可以在这里使用它.它被定义为:
instance Monoid b => Monoid (a -> b) where
mempty _ = mempty
mappend f g x = f x `mappend` g x
Run Code Online (Sandbox Code Playgroud)
所以mappend对于函数f和g应用f以及g参数,x并结合使用mappendmonoid类型的结果b.b这是一个列表,所以你最终得到了
my_ans2' = (f x) ++ (g x)
Run Code Online (Sandbox Code Playgroud)
这里f是diagFunc和g是diagFunc . transpose.
正如@chi在评论中指出的那样,你也可以使用一个应用解决方案:
import Control.Applicative
my_ans2'' = (++) <$> diagFunc <*> (diagFunc . transpose)
where diagFunc = transpose . zipWith (drop) [0..]
Run Code Online (Sandbox Code Playgroud)
这是更一般的,因为它不依赖于两个函数的返回类型是幺半群.