[Función] Un artículo lo lleva a comprender el flujo de control, la recursividad y las funciones de orden superior

Tabla de contenido

flujo de control

Declaraciones condicionales

declaración de iteración

Ejemplo: factorización prima

 

recursión

Ejemplo: Factorial

Ejemplo: Secuencia de Fibonacci

Ejemplo: juzgar números pares e impares

funciones de orden superior

expresión lambda

función de diseño

Ejemplo: cálculo acumulativo

Ejemplo: curry

Laboratorio 1: Funciones, Control

Tarea 2: Funciones de orden superior

Proyecto 1: El juego del cerdo


flujo de control

Declaraciones ejecutadas por el intérprete para realizar determinadas operaciones.

Por ejemplo, la instrucción compuesta completa (instrucción compuesta) se  def declara en Python; el encabezado  header determina el tipo de una instrucción simple (cláusula), que va seguida de una secuencia de instrucción (conjunto). El intérprete ejecutará esta secuencia de sentencias en un cierto orden.

Declaraciones condicionales

if Las declaraciones condicionales aparecen como palabras clave en la mayoría de los idiomas  .

En Python  True , y  False representa verdadero o falso, respectivamente, si conduce una declaración condicional y su rama verdadera, cero o uno más conduce a una rama falsa, y puede haber cero o más elifs para anidar.

def absolute_value(n):
    if n < 0:
        return -n
    elif n == 0:
        return 0
    else:
        return n

 En el esquema  #t y  #f representan verdadero o falso respectivamente, elif no se puede anidar en términos de gramática (if test consequent alternative)

(define (absolute-value n)
  (if (positive? n) n (- n)))

FP generalmente proporciona un conjunto de sintaxis tipo guardia, es decir, la declaración condicional puede aceptar cualquier número de juicios condicionales, y el juicio condicional se realiza de arriba a abajo. Cuando la condición es verdadera, el bloque de declaración se ejecuta y el condicional Se sale de la declaración Conforms tendrá un bloque predeterminado para ajustarse. De hecho, esta declaración es más como  if-then-elif-else una variante de .

(cond ((< n 0) (- n))
      ((= n 0) n)
      (else n))

En erlang, si es cond.

absolute_value(N) ->
    if
        N < 0 -> -N;
        N =:= 0 -> N;
        true -> N
    end.

declaración de iteración

La instrucción de iteración también se denomina instrucción de bucle, que ejecuta el cuerpo del bucle cuando se cumple la condición y sale hasta que no se cumple la condición.

i = 0
total = 0
while i < 3:
    total = total + i
    i = i + 1
    print(total)

print(total)
# 0
# 1
# 3

El bucle en el esquema es un poco diferente del while en el lenguaje normal, aunque es más como el for en el lenguaje C (o tal vez el for en C es más como el do en Lisp), no importa cómo lo digas , es una instrucción de bucle de cambio de variable.

(do ((i 0 (+ i 1)) (total 0 (+ total i))) ;; assignment
    ((> i 2) total) ;; exit
  (display total) ;; body
  (newline))
;; 0
;; 0
;; 1
;; 3 -- not print

 Como un FP puro, erlang no tiene una declaración while disponible y necesita ser simulado usando recursividad de cola.

loop(3, Total) -> Total;
loop(I, Total) -> loop(I + 1, Total + I).

 

Ejemplo: factorización prima

La factorización prima es un problema típico que necesita usar bucles y condiciones para encontrar la respuesta. Para cada entero positivo N, podemos descomponer el conjunto de todos sus factores primos:

  • 8 = 2 * 2 * 2
  • 9 = 3 * 3
  • 10 = 2 * 5
  • 11 = 11

Una mejor manera es encontrar el factor primo más pequeño de este entero positivo y luego continuar descomponiendo la parte restante hasta que se complete la descomposición.

858 = 2∗429 = 2∗3∗143 = 2∗3∗11∗13

(define (get-primes n)
  (let ((bits (make-vector (+ n 1) #t)))
    (let loop ((p 2) (ps '()))
      (cond ((< n p) (reverse ps))
            ((vector-ref bits p)
             (do ((i (+ p p) (+ i p))) ((< n i))
               (vector-set! bits i #f))
             (loop (+ p 1) (cons p ps)))
            (else (loop (+ p 1) ps))))))

(define (get-factorization n primes)
  (let ((prime (car primes))
        (others (cdr primes)))
    (if (= (remainder n prime) 0)
        prime
        (get-factorization n others))))

(define (prime-factorization n)
  (if (< n 3)
      (list n)
      (let ((primes (get-primes n)))
        (let loop ((num n) (ans '()))
          (cond ((= num 1) (reverse ans))
                (else (let ((prime (get-factorization num primes)))
                        (loop (quotient num prime) (cons prime ans)))))))))

 

recursión

Recursión En matemáticas e informática, el método de usar una función en sí misma en su definición. El término recursión también se usa más comúnmente para describir el proceso de repetir cosas de una manera similar a sí misma. Por ejemplo, cuando dos espejos son aproximadamente paralelos entre sí, las imágenes anidadas en los espejos aparecen en una recursión infinita. También puede entenderse como un proceso de autorreplicación.

Aquí hay una explicación que podría ser más útil para comprender el proceso recursivo:

  1. ¿Ya terminamos? Si lo hace, devuelva el resultado. Sin tal condición de terminación, la recursividad continuaría para siempre.
  2. Si no, simplifica el problema, resuelve el problema más fácil y ensambla el resultado en una solución al problema original. Luego regrese a esa solución.

Ejemplo: Factorial

Factorial(0)=1,

Factorial(1)=1,

Factorial(N)=N×Factorial(N−1)

(define (factorial n)
  (cond ((= n 0) 1)
        (else (* n (factorial (- n 1))))))

 En este proceso de cálculo, a través del modelo de sustitución, se puede ver que el cálculo es una forma que se expande gradualmente y luego se contrae. El proceso de cálculo construye una cadena formada, 推迟进行的操作y la etapa de contracción es la ejecución real de estas operaciones. Este cálculo se solicita el proceso 递归计算过程. Si se va a ejecutar este proceso, el intérprete debe mantener la trayectoria de las operaciones a realizar en el futuro.En este ejemplo, la longitud de la cadena de multiplicación que se difiere es la cantidad de información que se necesita guardar para salvar su trayectoria Esta longitud aumenta con el valor de n Y el crecimiento lineal, este proceso se llama computación recursiva lineal .

(factorial 5)
(* 5 (factorial 4))
(* 5 (* 4 (factorial 3)))
(* 5 (* 4 (* 3 (factorial 2))))
(* 5 (* 4 (* 3 (* 2 (factorial 1)))))
(* 5 (* 4 (* 3 (* 2 (* 1 (factorial 0))))))
(* 5 (* 4 (* 3 (* 2 (* 1 1)))))
(* 5 (* 4 (* 3 (* 2 1))))
(* 5 (* 4 (* 3 2)))
(* 5 (* 4 6))
(* 5 24)
120

 Veamos otra implementación.

(define (factorial n)
  (let factorial-iter ((product 1) (counter 1))
    (if (> counter n)
        product
        (factorial-iter (* counter product)
                        (1+ counter)))))

 No hay crecimiento ni contracción en este proceso de cálculo. En cada paso del proceso de cálculo, la trayectoria que debe guardarse es el valor actual de la  product suma  variable counter . Llamamos a este proceso un proceso de cálculo iterativo . Un proceso de cálculo iterativo es un proceso de cálculo cuyo estado se puede describir mediante un número fijo de variables de estado. Al mismo tiempo, existe un conjunto de reglas fijas que describen cómo se actualizan las variables de estado cuando el proceso de cálculo pasa de un estado a otro. También hay un La detección del estado final se utiliza para describir cómo se termina el proceso de cálculo.

(factorial-iter   1 1 5)
(factorial-iter   1 2 5)
(factorial-iter   2 3 5)
(factorial-iter   6 4 5)
(factorial-iter  24 5 5)
(factorial-iter 120 6 5)
120

 

Ejemplo: Secuencia de Fibonacci

Fibonacci(0)=0,

Fibonacci(1)=1,

Fibonacci(N)=Fibonacci(N−1)+Fibonacci(N−2)

Se puede ver que la secuencia de Fibonacci es una función naturalmente recursiva, y la función recursiva se ha encontrado en el código anterior, solo mire la implementación del código.

(define (fibonacci n)
  (cond ((= n 0) 0)
        ((= n 1) 1)
        (else (+ (fibonacci (- n 1))
                 (fibonacci (- n 2))))))

Si dibuja el gráfico de llamada de la función de Fibonacci, puede ver que se parece a un árbol, y tal recurrencia se llama  recursión de árbol . Pero hay muchos cálculos repetidos, lo que conducirá a cálculos sin sentido y desperdiciará el rendimiento de la CPU.

 

Debido a que este método de cálculo de la secuencia de Fibonacci es muy malo, realiza muchos cálculos redundantes y el número de recurrencias aumenta exponencialmente con el tamaño de n, por lo que necesitamos usar un método iterativo para optimizar el proceso de solución.

(define (fibonacci n)
  (let fibonacci-iter ((a 1) (b 0) (counter 1))
    (if (> counter n)
        b
        (fibonacci-iter (+ a b) a (+ counter 1)))))

 Los procedimientos de cálculo recursivo en árbol no son inútiles.Cuando se consideran operaciones sobre datos estructurados jerárquicamente en lugar de operaciones logarítmicas, los procedimientos de cálculo recursivo en árbol son una herramienta natural y poderosa para comprender y diseñar programas.

Ejemplo: juzgar números pares e impares

Si no puede usar directamente el método de módulo para determinar números pares o impares, entonces hay una manera simple y clara: pregunte si el número anterior es par/impar. Obviamente, esta es una pregunta recursiva, y debemos seguir preguntando hasta obtener una respuesta.

(define (odd? n)
  (if (= n 0)
      #f
      (even? (- n 1))))
(define (even? n)
  (if (= n 0)
      #t
      (odd? (- n 1))))

 Esta forma de hacer que múltiples funciones se llamen recursivamente se llama recursividad indirecta.

funciones de orden superior

Las funciones de orden superior  (Higher-Order Functions) son funciones que pasan funciones como parámetros y devuelven valores. Esta característica ocurre principalmente en lenguajes con características FP y, a menudo, estos lenguajes también proporcionan lambdas al mismo tiempo. .

expresión lambda

 Una expresión lambda  es una forma simplificada de definir una función que captura algunas variables en el entorno actual, también conocida como cierre. Lambda a menudo aparece con funciones de orden superior, generalmente cuando se pasa un predicado condicional, se crea un objeto lambda correspondiente en lugar de crear un paso de función.

(lambda (x)
  (= x 0))

Una lambda no es diferente de una función normal y consta de tres partes:  un encabezado  (la palabra clave lambda), una lista de parámetros y un cuerpo de función . Además, lambda no puede ser recursivo. Si desea recurrir a lambda, debe usar el combinador Y. 1  ,  2

Las variables de entorno capturadas en lambda se pueden usar directamente

(define (zero? x)
  ((lambda () (= x 0))))
(zero? 0) ;; #t
(zero? 1) ;; #f

función de diseño

Para una función, al diseñar una función, debe prestar atención a tres aspectos:

  1. Cada función debe tener solo una tarea precisa, y las funciones que realizan múltiples tareas deben dividirse en múltiples funciones
  2. No te repitas  (SECO, No te repitas), si alguna vez te encuentras copiando y pegando un fragmento de código, probablemente hayas visto la oportunidad de abstraerlo con funciones
  3. La función debe diseñarse para ser más general, como no proporcionar  cuadrado  y  cubo , pero proporcionar  pow , y especificar la potencia para realizar cuadrado y cubo respectivamente.

Ejemplo: cálculo acumulativo

Por ejemplo, ahora necesita calcular la acumulación, que incluye, entre otros \sum_{i=1}^{n}{i}, \sum_{i=1}^{n}{i^{2}} etc., de acuerdo con los tres aspectos de la función de diseño, ¡necesitamos diseñar una función para la acumulación! Además, esta función debe ser lo suficientemente abstracta para proporcionar generalidad.

Entonces puedo definir dos parámetros starty endse utilizan para identificar los límites superior e inferior de la función de acumulación, por lo que lo más importante es cómo acumular y cómo decir esta función. ¡Diseñe esta función como una función de orden superior!

 

(define (summation start end term)
  (let summation-iter ((counter start) (value 0))
    (if (> counter end)
        value
        (summation-iter (+ counter 1) (+ value (term counter))))))
(summation 0 10 (lambda (x) x))  ;; sum (i), 55
(summation 0 10 (lambda (x) (* x x))) ;; sum (i^2), 385
(summation 0 10 (lambda (x) (sqrt x))) ;; sum (sqrt(i)), 22.4682

Ejemplo: curry

Currying (currying) es una característica importante de las matemáticas y FP Es una técnica de convertir una función que recibe múltiples parámetros en una función que recibe un parámetro y devuelve una nueva función que recibe los parámetros restantes y devuelve el resultado. Entonces estas tres expresiones son equivalentes.

 

(define (sum a b) (+ a b))
(define (sum-curry a) (lambda (b) (+ a b)))
(define add10 (sum-curry 10))
(add10 5)  ;; 15
(sum 10 5) ;; 15

Laboratorio 1: Funciones, Control

(define (falling n k)
  "Compute the falling factorial of n to depth k."
  (define factorial
    (lambda (n)
      (cond ((= n 0) 1)
            ((= n 1) 1)
            (else (* n (factorial (- n 1)))))))
  (/ (factorial n)
     (factorial (- n k))))

 

(define (sum-digits n)
  "Sum all the digits of y."
  (let sum-digits-iter ((num n) (val 0))
    (if (= num 0)
        val
        (sum-digits-iter (quotient num 10) (+ val (remainder num 10))))))

(define (double-eights n)
  "Return true if n has two eights in a row."
  (let double-eights-iter ((num n) (prev #f))
    (if (= num 0)
        #f
        (let ((curr (= (remainder num 10) 8)))
          (or (and curr prev)
              (double-eights-iter (quotient num 10) curr))))))

Tarea 2: Funciones de orden superior

producto

         calculartérmino(1) \times término(2) \times \cdots \times término(n)

(define (product n term)
  "Return the product of the first n terms in a sequence."
  (let product-iter ((counter 1) (init 1))
    (if (> counter n)
        init
        (product-iter (+ counter 1) (* init (term counter))))))

 

acumular

         función de acumulación        

(define (accumulate merger init n term)
  "Return the result of merging the first n terms in a sequence and start.
    The terms to be merged are term(1), term(2), ..., term(n). merger is a
    two-argument commutative function."
  (let accumulate-iter ((counter 1) (value init))
    (if (> counter n)
        value
        (accumulate-iter (+ counter 1) (merger value (term counter))))))

 

Proyecto 1: El juego del cerdo

¡Lo sé! Usaré mis funciones de orden superior para ordenar tiradas más altas.

En Hog, dos jugadores se turnan para intentar acercarse a la meta, y el primer jugador en sumar al menos la meta gana, con una meta predeterminada de 100 puntos. En cada intento, el jugador selecciona hasta diez dados para tirar. La puntuación del jugador es la suma de todas las tiradas de dados de la ronda actual. Un jugador corre cierto riesgo si tira demasiados dados:

  • Sow Sad , si el resultado de cualquier dado es 1, la puntuación del turno del jugador actual es 1.

En un juego Hog normal, eso es todo. Para agregar algunas características del juego, agregaremos algunas reglas especiales:

  • Pig Tail , un jugador que elige lanzar 0 dados 2 \times \lvert{decenas - unidades}\rvert + 1 obtendrá puntos . donde tensy onesse refieren a los dígitos de las decenas y unidades de la puntuación del oponente.

  • Square Swine , cuando un jugador obtiene puntos en su turno y el resultado final es un cuadrado perfecto, establece su puntuación en el siguiente cuadrado perfecto.

Supongo que te gusta

Origin blog.csdn.net/qq_62464995/article/details/128474790
Recomendado
Clasificación