微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

javascript – 如何在Haskell中编写这个polyvariadic组合函数?

注意:这是作者删除another question的转贴.这是原始问题:

我在Javascript中有这个polyvariadic comp函数,并且想知道Haskell中的类似实现是否可行.我最感兴趣的是comp的类型:

const comp = f => Object.assign(
  g => comp([g].concat(f)),{run: x => f.reduce((acc,h) => h(acc),x)}
);

const inc = n => n + 1;
const sqr = n => n * n;
const repeatStr = s => n => Array(n + 1).join(s);

comp(repeatStr("*")) (inc) (sqr).run(2); // "*****"

comp(repeatStr("*"))
  (inc)
  (inc)
  (inc)
  (inc)
  (inc).run(0); // "*****"

comp构建一个异构数组,通常在Haskell中没有类型.我猜这种可变参数函数在返回类型中必须是多态的.但是,到目前为止,这项任务超出了我的Haskell知识.任何线索都会有所帮助.

上下文

我使用Javascript运行时类型检查器,以便我可以以类型安全的方式在comp中构建数组.它需要显式类型注释,并且仅支持参数和秩-2多态.

解决方法

你是对的.您无法在Haskell(1)中构建可组合函数的异构列表.但是,您可以为可组合函数创建自己的列表数据类型,如下所示:
{-# LANGUAGE GADTs #-}

data Comp a b where
    Id   :: Comp a a
    Comp :: Comp b c -> (a -> b) -> Comp a c

run :: Comp a b -> a -> b
run Id         = id
run (Comp g f) = run g . f

Id构造函数类似于[],Comp构造函数类似于:但是翻转了参数.

接下来,我们使用varargs pattern创建一个多变量函数.为此,我们定义了一个类型类:

{-# LANGUAGE MultiParamTypeClasses,FunctionalDependencies #-}

class Chain a b c | c -> a where
    chain :: Comp a b -> c

请注意,我们的状态是Comp b c,我们的结果是Comp b c或带有另一个函数(a – > b)作为输入的函数,并将其与我们的状态组合以生成一个名为r的新链,状态为Comp a c.我们现在为这些定义实例:

{-# LANGUAGE FlexibleInstances #-}

instance c ~ c' => Chain b c (Comp b c') where
    chain = id

instance Chain a c r => Chain b c ((a -> b) -> r) where
    chain g f = chain (Comp g f)

comp :: Chain b b c => c
comp = chain Id

现在可以将comp函数定义为链ID(即,以空列表Id作为其状态的链).我们最终可以像在JavaScript中一样使用这个comp函数

inc :: Int -> Int
inc = (+1)

sqr :: Int -> Int
sqr x = x * x

repeatStr :: String -> Int -> String
repeatStr s x = concat (replicate x s)

example1 :: String
example1 = comp (repeatStr "*") inc sqr `run` 2

example2 :: String
example2 = comp (repeatStr "*") inc inc inc inc inc `run` 0

把它们放在一起:

{-# LANGUAGE GADTs,MultiParamTypeClasses,FunctionalDependencies,FlexibleInstances #-}

data Comp a b where
    Id   :: Comp a a
    Comp :: Comp b c -> (a -> b) -> Comp a c

run :: Comp a b -> a -> b
run Id         = id
run (Comp g f) = run g . f

class Chain a b c | c -> a where
    chain :: Comp a b -> c

instance c ~ c' => Chain b c (Comp b c') where
    chain = id

instance Chain a c r => Chain b c ((a -> b) -> r) where
    chain g f = chain (Comp g f)

comp :: Chain b b c => c
comp = chain Id

inc :: Int -> Int
inc = (+1)

sqr :: Int -> Int
sqr x = x * x

repeatStr :: String -> Int -> String
repeatStr s x = concat (replicate x s)

example1 :: String
example1 = comp (repeatStr "*") inc sqr `run` 2

example2 :: String
example2 = comp (repeatStr "*") inc inc inc inc inc `run` 0

如您所见,comp的类型是Chain b b c => C.要定义Chain类型,我们需要MultiParamTypeClasses和FunctionalDependencies.要使用它,我们需要FlexibleInstances.因此,您需要一个复杂的JavaScript运行时类型检查器才能正确键入check comp.

编辑:在注释中指出naomikDaniel Wagner,您可以使用实际函数而不是可组合函数列表作为comp状态的内部表示.例如,在JavaScript中:

const comp = run => Object.assign(g => comp(x => g(run(x))),{run});

同样,在Haskell中:

{-# LANGUAGE GADTs,FlexibleInstances #-}

newtype Comp a b = Comp { run :: a -> b }

class Chain a b c | c -> a where
    chain :: Comp a b -> c

instance c ~ c' => Chain b c (Comp b c') where
    chain = id

instance Chain a c r => Chain b c ((a -> b) -> r) where
    chain g f = chain (Comp (run g . f))

comp :: Chain b b c => c
comp = chain (Comp id)

请注意,即使我们不再使用GADT,我们仍然需要GADTs语言扩展,以便在Chain的第一个实例中使用等式约束c~c’.另外,你可以看到运行g. f已从run的定义转移到Chain的第二个实例.同样,id已从run的定义移到comp的定义中.

(1)您可以使用存在类型在Haskell中创建异构函数列表,但它们不具有可组合的附加约束.

原文地址:https://www.jb51.cc/js/158017.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐