eps*_*lbe 5 polymorphism haskell dry
前几天我写了一个小程序来收集矩阵中的一堆数字 - data Matrix = Matrix [[Int]]从一个角落开始 - Corner并按照一个路径 - [Direction]所有这三种类型都是一个类的实例Transformable
然后我有一个函数,生成一个转换函数,转换给定的角和方向 - LeftUp和Right
turnLUR :: Transformable a => (Corner, Direction) -> a -> a
Run Code Online (Sandbox Code Playgroud)
然后我用这个函数"收获"矩阵中的所有数字:
harvest :: Matrix ? [(Corner,Direction)] ? [Int]
harvest _ [] = []
harvest (Matrix []) _ = []
harvest as (cd:csds) = b ++ harvest (Matrix bs) csds' --cd = (Corner,Direction)
where f1 = turnLUR cd -- Matrix -> Matrix
f2 = turnLUR cd -- Corner -> Corner
f3 = turnLUR cd -- Direction -> Direction
Matrix (b:bs) = f1 as -- b = first line of [[Int]]
fcfd (c,d) = (f2 c,f3 d)
csds' = map fcfd csds
Run Code Online (Sandbox Code Playgroud)
现在我的问题为什么我必须写下来f1,f2而f3不是使用一个函数f三次(在我的脑海中保持DRY!) - 所有三种类型Corners,Directions并且Matrix是实例class Transformable.
如何在没有制作"相同"功能的三个版本的情况下编写该代码?
ehi*_*ird 11
这是因为单态限制.给它一个显式的类型签名,你每次都可以重用相同的函数:
harvest :: Matrix ? [(Corner,Direction)] ? [Int]
harvest _ [] = []
harvest (Matrix []) _ = []
harvest as (cd:csds) = b ++ harvest (Matrix bs) csds' --cd = (Corner,Direction)
where f :: Transformable a => a -> a
f = turnLUR cd
Matrix (b:bs) = f as -- b = first line of [[Int]]
fcfd (c,d) = (f c,f d)
csds' = map fcfd csds
Run Code Online (Sandbox Code Playgroud)
或者,您可以通过放在{-# LANGUAGE NoMonomorphismRestriction #-}文件顶部将其关闭.
单态限制并不受欢迎 - 甚至GHC的手册也将其称为可怕的单态限制 - 但是有一些棘手的极端情况,特别是与共享相关(参见我链接的维基页面以获取更多信息),它避免了.在这种情况下,我建议只添加类型签名.