我正在大学的课程中学习Haskell,并且有一个考试练习,我们需要定义一个函数,它接受函数列表[(Int ->Int)]
和另一个类型Int
的参数返回Int
。所以Type应该是
compose :: [(Int ->Int)] -> Int -> Int.
该函数应从左到右返回列表中函数的组合,并将其应用于第二个参数。 我尝试了以下方法:
compose :: [(Int -> Int)] -> Int -> Int
compose [] x = x
compose (f:fs) x
|fs == [] = f x
|f : (compose fs x)
但编译器抛出错误:
003Exam.hs:24:22:
Couldn't match expected type ‘Int’ with actual type ‘[Int -> Int]’
In the expression: f : (compose fs x)
In an equation for ‘compose’:
compose (f : fs) x
| fs == [] = f x
| otherwise = f : (compose fs x)
003Exam.hs:24:28:
Couldn't match expected type ‘[Int -> Int]’ with actual type ‘Int’
In the second argument of ‘(:)’, namely ‘(compose fs x)’
In the expression: f : (compose fs x)
如果我离开最后一行,例如:
compose :: [(Int -> Int)] -> Int -> Int
compose [] x = x
compose (f:fs) x
|fs == [] = f x
然后我也得到一个错误 - 这是我真正不理解的错误:
003Exam.hs:23:13:
No instance for (Eq (Int -> Int))
(maybe you haven't applied enough arguments to a function?)
arising from a use of ‘==’
In the expression: fs == []
In a stmt of a pattern guard for
an equation for ‘compose’:
fs == []
In an equation for ‘compose’: compose (f : fs) x | fs == [] = f x
我很乐意帮助澄清我做错了什么。
答案 0 :(得分:6)
首先,(:)
仅用于添加列表前面的元素(或模式匹配),因此您必须替换
f : compose fs x
与
f (compose fs x)
接下来,您必须在警卫中使用类型为Bool
的表达式或模式匹配:
| fs == [] = -- this line is still wrong, see below
| otherwise = f (compose f xs)
但是,函数没有Eq
个实例。两个函数的等价性是不可判定的(通常),因此使用null :: [a] -> Bool
而不是(==) :: Eq a => [a] -> [a] -> Bool
:
compose :: [(Int -> Int)] -> Int -> Int
compose [] x = x
compose (f:fs) x
| null fs = f x
| otherwise = f (compose fs x)
由于compose [] x
与x
相同,您甚至可以删除支票:
compose :: [(Int -> Int)] -> Int -> Int
compose [] x = x
compose (f:fs) x = f (compose fs x)
compose [(+1), (+2)] 1
(将其替换为其定义),而不删除中间术语。你注意到一种模式吗?compose
。答案 1 :(得分:1)
your-blog-url.blogspot.com/feeds/posts/summary?redirect=false
我认为你的问题是这个冒号不应该在这里。
Haskell中的|f : (compose fs x)
^
是列表构造函数,这就是编译器告诉您正在尝试返回:
的原因。如果它不存在,则只需应用f并且您将返回[Int -> Int]
。
答案 2 :(得分:1)
您必须重复应用结果上的函数,并且应将空函数列表视为id。
for(var land in result.landen){
$.each(land, function() {
$.each(this, function(key, value) {
console.log(key + value);
});
});
}
我读错了,上面是从左到右应用功能。如果你从左到右合成(最右边的功能将首先应用),它应该是这样的(现在没有点)
Prelude> let comp :: [(Int->Int)] -> Int -> Int
Prelude| comp [] x = x
Prelude| comp (f:fs) x = comp fs (f x)
Prelude|
Prelude> comp [(^2),(+1)] 3
10
答案 3 :(得分:1)
从几个小时开始,让我提供一些关于将此作为折叠的提示。由于有两个方向你可以组成这些功能,而且我没有以正确的方式获得任何积分,我只会展示它们。
首先,一些样板:
import Data.Monoid (Dual (..))
import Control.Category (Category (..))
import Data.Foldable (Foldable (foldMap))
import Prelude hiding (id, (.))
接下来,解释monoid是一个只有一个对象的类别的类型:
newtype Cat c a = Cat { getCat :: c a a }
instance Category c => Monoid (Cat c a) where
mempty = Cat id
mappend (Cat f) (Cat g) = Cat (f . g)
最后,您寻求的功能从->
推广到任意Category
:
compose1 :: (Foldable f, Category c) => f (c a a) -> c a a
compose1 = getCat . foldMap Cat
compose2 :: (Foldable f, Category c) => f (c a a) -> c a a
compose2 = getCat . getDual . foldMap (Dual . Cat)
为读者练习:编写等效函数,将Category
替换为Semigroupoid
,将Foldable
替换为Foldable1
。
读者的另一个练习:使用Monoid (Cat c a)
和/或来自Data.Coerce.coerce
的{{1}}和#.
来编写.#
实例,以避免虚假的关闭分配。< / p>
P.S。 Data.Profunctor.Unsafe
类型只解释了故事的一半。以下是其余部分:
Cat
使用
可能更准确newtype Mon m a b = Mon m
instance Monoid m => Category (Mon m) where
id = Mon mempty
Mon m . Mon n = Mon (m `mappend` n)
但如果没有真正增加太多价值,效率就会降低。