返回文章列表

文章

Get Programming with Haskell-4

函数是一等公民

部分内容超过 Notion API 单页读取上限,已尽力加载可访问内容。

目录
  1. 1、Lambda functions as arguments
  2. 2、Example—custom sorting
  3. 2、Returning functions
  4. 使用动态分派
# First-class functions ## 1、Functions as arguments 函数作为参数,先看以下示例: ```haskell ifEvenInc n = if even n then n + 1 else n ``` ifEvenInc函数有一个参数n,如果n是even,则函数返回n+1,否则返回n,很简单,测试一下: ![](https://prod-files-secure.s3.us-west-2.amazonaws.com/4b1b167f-4b52-4031-8233-f4f2689af574/45f3acbe-1e7a-429a-9fcb-65653eab4e76/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466X24AGZLE%2F20261016%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20261016T231709Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjECYaCXVzLXdlc3QtMiJIMEYCIQCZ%2FujULKqSU8McfyTtxRpqXQgZJ4K9OT7om9AzFK9TcwIhAO343ZmVqr5DJg8BkQnyb8qbbGJVXdsWWssos9EQ%2FJEkKogECO%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEQABoMNjM3NDIzMTgzODA1IgzJ%2B%2F4sPQwqxiy5Rx8q3APYg5uAwZ0E%2BZIa%2BJzEHzgU2YltEKB4rg4trRzWHtPc3UbME9icqep3LAg4a3p98lO9xhIm7rcuaglTdmavHncwMH78Pn3d9QgimyEYnaPQjUPdBHUa6os5a28Tk%2Bna%2BC6meq7%2FuSGxU3rXjifS%2F8g8zm5CM2kzLQRliUy4c6v6O%2FQ66PhKpH0irObdh0ldCMmVLI7gu8A7f12Xjs6hccd2O4WT11Ecm46lhm0xBkbH2etXRdVvT1VTmjD7%2BpMZy%2FTax8REFD3GIwF5phR5nZjSMdj6WqirViUvA1W3bAB6dcMhNc%2FouvDnrVSs9wploOKl9eVyNF6dSMSBTf15j0zfxBZ5PRDa1Omh0Q7%2FexkoFVDw8AI%2FqSN5DP35XnQlQYy15QMqlMHuVJ2x5P%2FU2gJwIXCHd1NoDFRiK2JRsGGQL%2Bsm4ZCmUw6W4DcCBZDba20yFgk%2FihVt7hoOqKvv2tUl0w4VMMJoi26Kvu%2BARL2hgHYz7LAnAEngKd%2FK%2FuqtQ1AtJl%2FyWUXbsjjQH0fsRyMb7NtluIihv6CN1vVly72fBLe8wGhXr0w0kuQzm%2BZWX%2F8LxsTGQ2Dj3Xp0ExyfezdXS1lw1M1YMaBZLVI64Rg6QizlPDphhY3QWm%2B8ajDwu8rWBjqkAWfXtRbONbLfPumF6dJlKwAHdJJmpANO%2FPWmvsDIpp4InsDoTvCoo9qF3JECBBkBnZB9UYTvhNgQmXqyG0FeqAWA3rAFv7QOSaZr%2FPcRZbtrrxAIXbBLZUbqrXDGPs7bAb%2BoxKyDJZtrcryiJRzcoaUSp0jFeE4hHZ8uJqiAMuixeHB4CihSLMRixcXzhfLmiPbuUg9RYzNCya0ZLg7OVJ%2FM%2Fq82&X-Amz-Signature=0111a80c35e7d903d530c0fa4492cdffb41a590dd40403644b98afb0052aea0f&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject#notion_record=block.1d15c571-bb7d-80ea-9aaf-c206770d7bce.4b1b167f-4b52-4031-8233-f4f2689af574) 我们再写几个类似的函数 ```haskell ifEvenDouble n = if even n then n * 2 else n

ifEvenSquare n = if even n then n ^ 2 else n

这些个函数其实都是一个模式,都是判断参数n是不是even,如果是则进行“**某种操作**”,否则直接返回n,我们抽象一个这种模式,将这“某种操作”是不是可以抽象成一个function,然后重新梳理以下这类函数的模式,参数n如果是even, 我们就function n,否则返回n,然后就是这种形式了
```haskell
ifEven myFunc n = if even n
    then myFunc n
    else n

这个myFunc 可以是 inc n = n + 1 , double n = n * 2, square n = n ^ 2等等等,测试一下这个是否可行: 事实证明,这个完全是可行的,那么我们是不是可以推广一下这个函数,其实n → n也是一个函数

ifEven1 myFunc1 myFunc2 n = if even n
    then myFunc1 n
    else myFunc2 n

已经显而易见了,一切都是这么自然合乎逻辑

1、Lambda functions as arguments#

上一节我们都是用命名函数,那么用lambda是不是也可以呢,当然,因为理论上所有的命名函数都可以和匿名函数互换

ifEven (\x -> x + 1) 3

2、Example—custom sorting#

将函数作为参数传递给另外一个函数最实际的用途是排序,下面的example中我们会使用tuple和list,tuple是一种和列表相似的数据类型,只不过tuple可以存放多种不同类型的元素且存放元素的大小个数是固定: author = (”Will”, “Kurt”) 这种只有2个item的tuple(又称作a pair)有两个有用的函数,fst和snd,作用分别是访问tuple的第一个和第二个元素

names = [("Ian", "Curtis"),
         ("Bernard", "Summer)",
         ("Peter", "Hook"),
         ("Stephen", "Morris")
        ]

对于list的排序haskell中已经有了内置的排序函数sort。要使用它,我们要import Data.List模块,使用方式如下:

import Data.List

从这个排序结果看,是按照first name的字母表顺序来排序的,那么我们如果想按照last name来排序怎么办呢?当然这是一种常规需求,Haskell在Data.List模块中也提供了相应的函数 sortBy,sortBy有一个自定义排序的方式的函数作为参数,我们可以定义一个按last name大小升序来排序的函数,使用方式是这样的:

compareLastName name1 name2 = if lastName1 > lastName2
    then GT
    else if lastName1 < lastName2
        then LT
        else EQ
    where lastName1 = snd name1
          lastName2 = snd name2

2、Returning functions#

我们已深入探讨了将函数作为参数传递(passing functions as arguments)的诸多应用,但这仅展现了一等函数(first-class functions)作为值的能力之半壁。函数亦可返回值,因此真正的"一等公民"函数,必然包含返回其他函数(return other functions)的能力。此时开发者不禁要问:为何需要返回函数呢? 一个典型场景是——基于特定参数动态分派函数(dispatch functions)。

  • PO Box 1234,San Francisco,CA,94111
  • PO Box 789,New York,NY,10013
  • PO Box 456,Reno,NV,89523 您需要构建一个函数,该函数将接受一个名称tuple(如您之前在排序示例中使用的那样) 和一个办公室位置,然后为您整理邮件地址。此函数的第一遍可能如下所示。我们需要介绍的唯一一件你还没有看到的事情是用于连接字符串 (和列表) 的++运算符。
addressLetter name location = nameText ++ " - " ++ location
  where
    nameText = (fst name) ++ " " ++ (snd name)