Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Haskell中任意组合多个地图_Haskell - Fatal编程技术网

在Haskell中任意组合多个地图

在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) 但是没有

如何在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)
但是没有用。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