在Haskell中任意编写许多映射

时间:2017-10-26 11:11:33

标签: 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)

但无济于事。哈斯克尔认为我正构建一个无限类型。 这显然是错误的,因为定义的函数对任何函数都是有限的 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

此外,暂时搁置这个问题的人甚至都没有理解这个问题...

1 个答案:

答案 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