关于为Path包添加Read实例及查找文件路径解析函数的技术咨询
嘿,我太懂你用Path包时遇到的这个困扰了——这个包的强类型路径确实能帮我们避免很多无效路径的坑,但官方没提供Read实例这点,确实在需要序列化/反序列化的时候挺闹心的!
首先得说清楚:Path官方故意没加Read实例,因为Read的默认行为太宽松,很容易把无效字符串解析成Path,违背了这个包“只存合法路径”的设计初衷。不过你要的四个实例(对应Path Abs File、Path Rel File、Path Abs Dir、Path Rel Dir这四种类型),其实完全可以借助Path本身提供的解析函数来实现,或者找社区已经写好的方案。
先找现成的社区方案
你可以在Hackage上搜索和Path相关的扩展包,关键词试试path read instance或者path extra——很多社区开发者已经封装了这类缺失的实例,比如有些包会专门补全Path的通用型类实例(包括Read、Show的增强版),直接安装用就行,省得自己写。
如果要自己实现,其实很简单
要是找不到合适的现成包,自己写也不麻烦,核心就是复用Path官方提供的安全解析函数:
parseAbsFile:解析绝对路径文件parseRelFile:解析相对路径文件parseAbsDir:解析绝对路径目录parseRelDir:解析相对路径目录
这些函数已经帮你处理了所有路径的特殊情况——比如Windows的反斜杠、Unix的斜杠、相对路径的./..、非法字符过滤等等,完全符合Path的安全要求。
给你一个直接可用的实现示例:
{-# LANGUAGE FlexibleInstances #-} import Path (Path, Abs, Rel, File, Dir) import Path.Parse (parseAbsFile, parseRelFile, parseAbsDir, parseRelDir) -- 通用辅助函数,减少重复代码 mkRead :: (String -> Either String a) -> Int -> String -> [(a, String)] mkRead parser _ s = case parser s of Right path -> [(path, "")] Left _ -> [] -- 为四种Path类型分别实现Read实例 instance Read (Path Abs File) where readsPrec = mkRead parseAbsFile instance Read (Path Rel File) where readsPrec = mkRead parseRelFile instance Read (Path Abs Dir) where readsPrec = mkRead parseAbsDir instance Read (Path Rel Dir) where readsPrec = mkRead parseRelDir
这里的mkRead函数把通用的解析逻辑抽出来,四个实例只需要对应不同的解析函数就行。注意要开启FlexibleInstances扩展,因为我们是给带类型参数的Path做实例。
小提醒
如果你需要更严谨的readsPrec行为(比如处理输入字符串中剩余的非路径字符),可以调整mkRead里的逻辑,比如用break分割字符串,但一般来说,直接把整个输入字符串当作路径解析就足够日常使用了。
内容的提问来源于stack exchange,提问作者user855443

