如果我有一个已知列表A :: [Int]
,并希望获得一个新列表B = newList A
,newList
定义如下:
newList :: [Int] -> [Int]
newList [] = []
newList (a:as) | a==0 = f(a) : newList (as)
| a==1 = g(a) : newList (as)
| otherwise = h(a) : newList (as)
其中f, g, h :: Int -> Int
是不重要的功能。
除了B
之外,我还想知道0, 1
分别有多少A
。
但是,由于递归生成B
时,它已经检查了a== (0 or 1)
中每个元素是否A
,因此再次检查它是一种冗余。
是否可以获得B
,但同时只需检查0, 1
A
中有多少private void button1_Click(object sender, EventArgs e)
{
var fileDialog1 = new OpenFileDialog
{
InitialDirectory = "c:\\",
RestoreDirectory = true
};
if (fileDialog1.ShowDialog() == DialogResult.OK)
{
System.Diagnostics.Process.Start(fileDialog1.FileName);
}
}
?
答案 0 :(得分:4)
这不是您正在寻找的答案,但您的功能背后有一个很好的抽象结构,所以我会留在这里:
import Data.Monoid
import Data.Functor
import Data.Traversable
import Control.Arrow
import Control.Monad.Trans.Writer
wr :: Int -> Writer (Sum Int, Sum Int) Int
wr 0 = tell (Sum 1, Sum 0) $> f 0
wr 1 = tell (Sum 0, Sum 1) $> g 1
wr n = return $ h n
collect :: [Int] -> ([Int], (Int, Int))
collect = second (getSum *** getSum) . runWriter . traverse wr
求和是一个幺半群,双求和是一个幺半群,Writer
monad处理幺半群,traverse
映射一个带有效函数的列表并执行所有效果。
此:
f = (+ 1)
g = (+ 2)
h = (+ 3)
main = print $ collect [0, 1, 2, 3, 0, 0, 0, 4, 1]
打印([1,3,5,6,1,1,1,7,3],(4,2))
- 四个零和两个。