如何定义多重合成功能?

时间:2014-10-25 17:41:28

标签: haskell functional-programming

有没有办法定义一个Haskell函数,它接受一个(某种类型的集合)函数并产生一个函数:它们的组成从右到左?

我试过了:

foldr ($)

但是这只接受一个函数列表,其结果与其参数的类型相同:

foldr ($) :: a -> [a -> a] -> a

所以,我可以这样做:

foldr ($) 5 [(+) 1, (*) 2] 这会产生正确的结果11

然而,试图评估这个:

foldr ($) "hello" [(+) 1, length]

产生以下错误:

错误 - 在列表中输入错误

*** Expression : [(1 +),length] *** Term : length *** Type : [a] -> Int *** Does not match : Int -> Int

2 个答案:

答案 0 :(得分:5)

一如既往,让我们在各处输入类型注释。

-- foldr ($) "hello" [(+) 1, length]
($) :: (a -> b) -> a -> b
"hello" :: [Char]
(+) 1 :: Num a => a -> a
length :: [a] -> Int
[(+) 1, length] :: ?!

原生Haskell列表不能包含不同类型的项目。

所以让我们退一步吧。我将使用<>来表示“我们想要的列表是什么”。我们不希望收集随机类型的东西。 < (+) 1, length >没问题,但< length, (+) 1 >不是,或者说我们需要一个实例Num [a]。同样,如果我们有两个以上的项目:每个项目的类型必然与其邻居相关。此外,整体列表的类型仅与第一个和最后一个成员的类型相关:什么是起始类型和结束类型?

我们可以用GADT来做到这一点:

{-# LANGUAGE GADTs #-}
module SO26565306 where

data F a b where
  FNil :: F a a
  (:&) :: (b -> c) -> F a b -> F a c

infixr 5 :&

runF :: F a b -> a -> b
runF FNil = id
runF (f :& fs) = f . runF fs

f :: F [a] Int
f = (+) 1 :& length :& FNil

ghci> runF f "hello"
6

f是您所需的< (+) 1, length >“列表”的实现。

还有一些F可能 - FunctorCategory个实例的详细说明 - 但我并没有真正看到它的用处。我们所做的就是人为地在普通函数组合上强加数据结构。我们甚至不能使用GHC的overloaded list notation,它不具备足够的灵活性。此外,插入所有GADT构造函数将阻止优化,几乎可以肯定包括列表融合。 (我没有仔细试验或仔细考虑过。)

回答你的问题

是的,可以定义一个Haskell函数,该函数接受一系列函数,这些函数具有不同但可组合的类型,并生成它们的组合。我演示的集合类型需要GADTs扩展名,即not available in Hugs,您似乎正在使用的编译器。此外,你不能真正做这个集合。我没有证明这一点,但是我会断言,对于F a b类型的值,除了将其分解为a -> b之外,您无法对其进行任何操作。它的组件功能通过模式匹配。

换句话说,你所询问的内容在Haskell中确实是可以表达的,并不清楚以这种方式做这件事有什么好处。

其他问题

正如我们在评论中所讨论的那样,您似乎正在寻找Clojure传感器的Haskell类比。你想就这个话题开一个新问题吗?它比这个更精确,更有针对性。

底线

为什么不使用((+) 1) . length

答案 1 :(得分:2)

Haskell List仅允许相同类型的元素。就像你不能拥有

一样
["one", 2]

因为"one"String2Int。你也不能拥有

[(+) 1, length]

因为(+) 1Int -> Intlength[a] -> Int