有没有办法定义一个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
答案 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
可能 - Functor
和Category
个实例的详细说明 - 但我并没有真正看到它的用处。我们所做的就是人为地在普通函数组合上强加数据结构。我们甚至不能使用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"
是String
而2
是Int
。你也不能拥有
[(+) 1, length]
因为(+) 1
是Int -> Int
而length
是[a] -> Int