很抱歉提出这个问题,但是在我看来,它破坏了参照透明性。
在研究问题并将其分解(问题是获得列表列表的对角线元素)时,我想到了这个(正确工作)的解决方案:
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
(注意,它两次包含中间行,这对我的用例来说不是问题)
现在显然可以很容易地对其进行重构。在首次尝试以无点样式编写它之后,我发现通过这些尝试简单地以非无点形式编写它会更容易:
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..]
现在,这些编译和工作都没有使我感到困惑,因为这似乎会破坏参照透明性。有人可以解释为什么我对此有误,以及如何正确编写此函数(加分点是我无法做到的,以无点格式编写)。
供参考,错误在这里:
/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)’
同样,我非常确定我对此有误,我只需要有人指出如何做即可。:) 提前致谢。
您可以使用以下方法修复它:
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..]
问题是将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..]
function的monoid实例可用于返回monoidal值的函数。由于列表是monoid,其中mappend
=(++)
可以在这里使用。它定义为:
instance Monoid b => Monoid (a -> b) where
mempty _ = mempty
mappend f g x = f x `mappend` g x
因此,mappend
对于函数f
,g
applyf
和g
论点x
,并将结果组合在一起使用mappend
于monoid类型b
。b
这是一个列表,所以您最终得到
my_ans2' = (f x) ++ (g x)
f
现在diagFunc
和g
现在在哪里diagFunc . transpose
。
正如@chi在评论中指出的,您还可以使用适用的解决方案:
import Control.Applicative
my_ans2'' = (++) <$> diagFunc <*> (diagFunc . transpose)
where diagFunc = transpose . zipWith (drop) [0..]
这是更通用的,因为它不依赖于两个函数的返回类型为monoid。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句