在Haskell中任意组合多个地图
如何在Haskell中合成n个贴图? 我试过递归地做:在Haskell中任意组合多个地图,haskell,Haskell,如何在Haskell中合成n个贴图? 我试过递归地做: composeMap 0 f = (\x -> x) composeMap n f = (.) f (composeMap (n-1) f) 迭代地: composeMap' n k f g = if n == k then g else composeMap' n (k+1) f (f . g) composeMap n f = composeMap' n 0 f (\x -> x) 但是没有
composeMap 0 f = (\x -> x)
composeMap n f = (.) f (composeMap (n-1) f)
迭代地:
composeMap' n k f g =
if n == k then g
else composeMap' n (k+1) f (f . g)
composeMap n f = composeMap' n 0 f (\x -> x)
但是没有用。Haskell认为我在构造一个无限类型。
这显然是错误的,因为定义的函数对于任何对象都是有限的
n>=0
有什么建议吗
一些人发布了将f视为具有以下类型签名的解决方案:
f :: a -> a
但是,我希望这对f s.t.有效。f具有以下多态性:
f :: a -> a'
f :: a' -> a''
特别是,我想要一个适用于函数映射的函数,具有可能的类型签名:
map :: (a -> b) -> [a] -> [b]
map (polymorphic) :: ([a] -> [b]) -> [[a]] -> [[b]]
该函数编译得非常好,但Haskell推断出以下类型签名,这不是我想要的:
composeMap'' :: Int -> (b -> b) -> b -> b
我甚至尝试过在单子中包装映射,但Haskell仍然认为我在构造一个无限类型:
composeMap n f = foldl (>>=) f (replicate n (\x -> return (map x)))
编辑:
我用下面的Haskell代码模板得到了我想要的。很甜蜜
这用于声明组合映射函数:
composeMap :: Int -> Q Dec
composeMap n
| n >= 1 = funD name [cl]
| otherwise = fail "composeMap: argument n may not be <= 0"
where
name = mkName $ "map" ++ show n
composeAll = foldl1 (\fs f -> [| $fs . $f |])
funcs = replicate n [| map |]
composedF = composeAll funcs
cl = clause [] (normalB composedF) []
composeMap::Int->Q Dec
复合物
|n>=1=基金名称[cl]
|否则=fail“composeMap:argument n可能不是恐怕我遗漏了一些东西。您的第一个实现对我来说编译并运行良好(ghc 8.0.2)
您的第二个实现未能编译,因为您忘记了else子句中的“
。这是我的完整源文件:
composeMap1 0 f = (\x -> x)
composeMap1 n f = (.) f (composeMap1 (n-1) f)
composeMap2' n k f g =
if n == k then g
else composeMap2' n (k+1) f (f . g)
composeMap2 n f = composeMap2' n 0 f (\x -> x)
还有一些测试
λ: :l question.hs
[1 of 1] Compiling Main ( question.hs, interpreted )
Ok, modules loaded: Main.
λ: doubleQuote = composeMap1 2 (\x -> "'" ++ x ++ "'")
λ: doubleQuote "something"
"''something''"
λ: doubleQuote = composeMap2 2 (\x -> "'" ++ x ++ "'")
λ: doubleQuote "something"
"''something''"
λ: plusThree = composeMap1 3 (+1)
λ: plusThree 10
13
λ: plusThree = composeMap2 3 (+1)
λ: plusThree 10
13
虽然Haskell对每个n
都是有限的,但它是静态类型的。这意味着函数的类型不能依赖于参数的值。在这种情况下,有没有办法绕过类型系统?您对composeMap
的第一个定义在这里工作得很好。您的第二个定义在我添加“
后也可以工作得很好>到递归调用。我投票结束。如果我正确解释了您的澄清,那么您希望composemap2map
的行为类似于map.map
和composemap3map
的行为类似于map.map.map
等等。这样正确吗?map.map
的类型是(a->b)->[[a]]->[[b]]
和map.map.map
是(a->b)->[[a]]]->[[b]]]
,也就是说,您希望composeMap
的输出值的类型取决于输入n
的值(它总是类型Eq a,Num a=>a
)。我认为这是不可能的,但可能是使用依赖类型,或者可能是一些涉及动态类型的黑客攻击。您不需要依赖类型。这是使用具有重叠实例的类型类可以做的事情(此外,在这种情况下,我想您需要类型族),但这并不经常发生,因为这是一种末了的抽象;你开始失去类型推理,很难在它们之上构建任何有用的东西。但是这种事情对于摆脱样板文件、节省程序员的击键或脑力开销,或者使API在l值上看起来更漂亮一点都很有用类型的级别和丑陋程度更高。正如我在帖子中所阐明的,我不希望函数只在签名类型的f上工作。f::a->a
@Raskell那么你希望你的函数有什么类型?@Carl可能类型系统不能处理我想要的,实际上,它是依赖于类型的。@Will Ness什么?显然有一个'代码>。我从源文件(已编译)复制粘贴了此代码,但未进行编辑。是的。我没有正确阅读。抱歉…:)
λ: :l question.hs
[1 of 1] Compiling Main ( question.hs, interpreted )
Ok, modules loaded: Main.
λ: doubleQuote = composeMap1 2 (\x -> "'" ++ x ++ "'")
λ: doubleQuote "something"
"''something''"
λ: doubleQuote = composeMap2 2 (\x -> "'" ++ x ++ "'")
λ: doubleQuote "something"
"''something''"
λ: plusThree = composeMap1 3 (+1)
λ: plusThree 10
13
λ: plusThree = composeMap2 3 (+1)
λ: plusThree 10
13