如何将部分函数应用于元组列表

时间:2016-03-08 03:58:16

标签: haskell

这个问题的标题可能听起来有误导性,但我不确定如何解释我想要做的事情。

我正在尝试使用非确定性数据结构。我正在尝试生成一组部分应用运算符和元组列表的所有可能组合:

-- test.hs
makeTupleList :: (Int, Int) -> [(Int, Int)] 
makeTupleList (a, b) = ZipList [(+2), (-2)] <*> ZipList [a, b]

我希望makeTupleList返回类似的内容:

[(a + 2, b + 2), (a + 2, b - 2), (a - 2, b + 2), (a - 2, b - 2)]

但我显然做错了,因为我一直收到这个错误:

Couldn't match type `ZipList' with `[]'

我如何得到我想要的结果?

2 个答案:

答案 0 :(得分:4)

您声明的类型与该函数实际具有的类型不匹配。

让我们只检查函数的主体

*> :t \(a, b) -> ZipList [(+2), (-2)] <*> ZipList [a, b]
\(a, b) -> ZipList [(+2), (-2)] <*> ZipList [a, b]
  :: (Num (b -> b), Num b) => (b, b) -> ZipList b

EEP!那根本不好。

所以让我们修复错误。第一个错误是-2绊倒了你,因为它解析为负2,而不是操作符部分。

你可以通过类型检查看到那个片段:

*> :t (-2)
(-2) :: Num a => a

好的,我们将其更改为显式的lambda,然后更接近:

*> :t \(a, b) -> ZipList [(+2), (\x -> x - 2)] <*> ZipList [a, b]
\(a, b) -> ZipList [(+2), (\x -> x - 2)] <*> ZipList [a, b]
  :: Num b => (b, b) -> ZipList b

现在我们看到了概念错误(如果你测试它,你可以看到更多)。我们刚刚回来[a+2,b-2]。 ziplist 的作用 - &#34;拉链&#34;列表在一起。它没有采用交叉产品。

现在我们看到我们处于完全错误的轨道上。

当我们想采取&#34;产品&#34;组合,我发现最自然的方式是使用列表理解。所以,让我们这样做吧。

makeTupleList (a,b) = let funs = [(+2),(\x->x-2)]
                      in [(f a, g b) | f <- funs, g <- funs]

这似乎就是这样。

*> makeTupleList (10,20)
[(12,22),(12,18),(8,22),(8,18)]

答案 1 :(得分:4)

我会放弃ZipList:

makeTupleList :: (Int, Int) -> [(Int, Int )]
makeTupleList (a,b) = (,) <$> aList <*> bList
 where
  functionList :: [Int -> Int]
  functionList = [flip (-) 2  ,(+ 2) ]
  aList :: [Int]
  aList = functionList <*> [a]
  bList = functionList <*> [b]

产量:

 λ> makeTupleList (1,1)
 [(-1,-1),(-1,3),(3,-1),(3,3)]

ZipList用于不从应用操作中生成排列。