努力使用纯函数编程来解决日常问题

如何解决努力使用纯函数编程来解决日常问题

| 我今天在黑客新闻中看到了这篇文章。我在理解纯函数式编程将如何帮助我抽象一个现实问题方面遇到同样的问题。 7年前,我从命令式编程转换为面向对象编程。我觉得我已经掌握了它,并且对我很有帮助。在过去的几年中,我学到了一些函数编程的技巧和概念,例如map和reduce,我也喜欢它们。我在OO代码中使用了它们,对此感到满意,但是在抽象一组指令时,我只能想到OO抽象来使代码更漂亮。 最近,我一直在研究python中的问题,并且一直在尝试避免使用OO来解决它。在大多数情况下,我的解决方案看起来势在必行,而且我知道如果使用OO,可以使它看起来更干净。我以为我可以发布问题,也许功能专家可以提出一个既美观又实用的解决方案。如果必须的话,我可以发布我的丑陋代码,但宁愿不发布。 :)这是问题所在: 用户可以请求图像或图像的缩略图。如果用户要求图片的缩略图,但该缩略图尚不存在,请使用python的PIL模块创建该缩略图。另外,还应创建一条具有可读路径的原始链接或缩略图的符号链接,因为原始图像名称是哈希码,而不是其内容的描述性内容。最后,重定向到该图像的符号链接。 在OO中,我可能会创建一个SymlinkImage基类,ThumbnailSymlinkImage子类和OriginalSymlinkImage子类。共享数据(在SymlinkImage类中)将类似于原始数据的路径。共享行为将创建符号链接。子类将实现一个名为\'generate \'之类的方法,该方法将负责创建缩略图(如果适用),并调用其超类以创建新的符号链接。     

解决方法

        是的,您实际上会使用功能性方法来进行此操作。 这是使用默认的纯函数式编程语言Haskell的草图。我们针对您的问题的关键概念创建新的类型,并将工作分解为离散的函数,这些函数一次执行一项任务。 IO和其他副作用(如创建符号链接)仅限于某些功能,并以类型指示。为了区分两种操作模式,我们使用求和类型。
--
-- User can request an image or a thumbnail of the image.
-- If the user requests the thumbnail of the image,and it doesn\'t yet exist,create it using
-- python\'s PIL module. Also create a symbolic link to the original or
-- thumbnail with a human readable path,because the original image name is a
-- hashcode,and not descriptive of it\'s contents. Finally,redirect to the
-- symbolic link of that image.
--

module ImageEvent where

import System.FilePath
import System.Posix.Files

-- Request types
data ImgRequest = Thumb ImgName | Full ImgName

-- Hash of image 
type ImgName = String

-- Type of redirects
data Redirect

request :: ImgRequest -> IO Redirect
request (Thumb img) = do
    f <- createThumbnail img
    let f\' = normalizePath f
    createSymbolicLink f f\'
    return (urlOf f)

request (Full img)  = do
    createSymbolicLink f f\'
    return (urlOf f)
    where
        f  = lookupPath img
        f\' = normalizePath f
连同一些助手,我将把定义交给您。
-- Creates a thumbnail for a given image at a path,returns new filepath
createThumbnail :: ImgName -> IO FilePath
createThumbnail f = undefined
    where
        p = lookupPath f

-- Create absolute path from image hash
lookupPath :: ImgName -> FilePath
lookupPath f = \"/path/to/img\" </> f <.> \"png\"

-- Given an image,construct a redirect to that image url
urlOf :: FilePath -> Redirect
urlOf = undefined

-- Compute human-readable path from has
normalizePath :: FilePath -> FilePath
normalizePath = undefined
一个真正美丽的解决方案将使用数据结构抽象出请求/响应模型,以表示要执行的命令序列。一个请求进入,建立一个纯粹的结构来表示它需要完成的工作,然后通过执行诸如创建文件之类的操作将其交给执行引擎。然后,核心逻辑将完全是纯函数(不是这个问题中有很多核心逻辑)。对于这种具有效果的真正纯函数式编程风格的示例,我推荐Wouter Swiestra的论文《野兽之美:尴尬小队的功能语义》     ,我个人认为问题是您正在尝试使用函数式编程来解决为命令式编程设计/陈述的问题。三种流行的范例(功能,命令,面向对象)具有不同的优势: 函数式编程通常以输入/结果的形式强调要执行的操作。 命令式编程强调如何做某事,通常是按照要采取的步骤的清单和顺序,以及要修改的状态。 面向对象编程强调系统中实体之间的关系 因此,当您处理问题时,首要任务是重新表述该问题,以便预期的范例可以正确解决该问题。顺便说一下,据我所知,作为副节点,没有“纯OOP”这样的东西。 OOP类的方法(Java,C#,C ++,Python或Objective C)中的代码都是必须的。 回到您的示例:陈述问题的方式(首先,然后也是,最后)是本质上必须的。因此,构建功能性解决方案几乎是不可能的(即不进行副作用或monad之类的技巧)。同样,即使您创建了一堆类,这些类本身也是无用的。要使用它们,您必须编写命令式代码(尽管这些代码已嵌入类中)才能逐步解决问题。 重述该问题: 输入:图像类型(完整或缩略图),图像名称,文件系统 输出:请求的图像,带有请求图像的文件系统 从新的问题陈述中,您可以像这样解决它:
def requestImage(type,name,fs) : 
    if type == \"full\" :
        return lookupImage(name,fs),fs
    else:
        thumb = lookupThumb(name,fs)
        if(thumb) :
            return thumb,fs
        else:
            thumb = createThumbnail(lookupImage(name,fs))
            return thumb,addThumbnailToFs(fs,thumb)
当然,这是不完整的,但是我们总是可以以大致相同的方式递归地解决lookupImage,lookupThumb,createThumbnail和addThumbnailToF。 注意:创建新文件系统听起来很麻烦,但事实并非如此。例如,如果这是较大的Web服务器中的模块,则“新文件系统”可以与新缩略图应在何处的指令一样简单。或者,在最坏的情况下,将缩略图放置到适当的位置可能是IO monad。     ,        改变思维方式的唯一方法就是改变思维方式。我可以告诉您什么对我有用: 我想从事需要并发的个人项目。我环顾四周,发现了erlang。我之所以选择它,是因为我认为它为并发提供了最好的支持,而不是出于其他任何原因。我以前从未使用过函数式语言(为了比较,我从1990年代初开始进行面向对象的编程。) 我读了阿姆斯特朗的二郎本。辛苦了我有一个小项目要进行,但是我一直在努力。 该项目失败了,但是几个月后,我已经将所有内容都绘制在脑海中,以至于我不再像以前那样思考对象。 我确实经历了将对象映射到erlang进程的阶段,但这还不算太长,我就摆脱了。 现在,切换范例就像切换语言,或从一辆车到另一辆车。驾驶父亲的汽车与卡车的感觉不一样,但是很快就可以习惯了。 我认为使用Python工作可能会使您退缩,因此强烈建议您检查erlang。它的语法非常陌生-但这也很好,因为较传统的语法(至少对我而言)会导致尝试以旧的方式对其进行编程而感到沮丧。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-