如何在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)
但无济于事。哈斯克尔认为我正构建一个无限类型。 这显然是错误的,因为定义的函数对任何函数都是有限的 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
我甚至尝试用monad包装地图,但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 Exp
composeMap n = do
f <- newName "f"
maps <- composedF
return $ LamE [(VarP f)] (AppE maps (VarE f))
where
composeAll = foldl1 (\fs f -> [| $fs . $f |])
funcs = replicate n [| map |]
composedF = composeAll funcs
此外,暂时搁置这个问题的人甚至都没有理解这个问题...
答案 0 :(得分:1)
恐怕我错过了什么。你的第一个实现编译并且对我来说很好(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