也许你还没有为函数应用足够的参数?

时间:2016-02-24 15:24:24

标签: haskell

我正在大学的课程中学习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

我很乐意帮助澄清我做错了什么。

4 个答案:

答案 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 [] xx相同,您甚至可以删除支票:

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)

但如果没有真正增加太多价值,效率就会降低。