You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Haskell中实现类似JavaScript的多元复合函数?

Great question! Let's break down how to implement JavaScript's comp function in Haskell, focusing on type safety and the unique challenges of handling that "heterogeneous function chain" you mentioned.

First, let's recap what your JavaScript comp does: it builds a chain of functions where each new function is added to the "inner" side (closer to the input value), and calling .run(x) applies all functions in reverse order of addition (so comp(f)(g)(h).run(x) equals f(g(h(x)))).

Key Observations About Haskell's Type System

Haskell doesn't have heterogeneous arrays like JavaScript, but its static type system actually makes this kind of function composition safer and more elegant—we don't need runtime checks because the compiler enforces that each function's output type matches the next function's input type.

Implementing a Haskell Equivalent of comp

We can use type classes to handle the variable-argument behavior, similar to how Haskell's printf works. Here are two approaches:

1. Variable-Argument Function (No Explicit run Method)

This approach lets us call comp with any number of functions, and it returns a final function that we can directly apply to our input:

-- Define a type class to handle variable-length function chains
class CompChain r where
  compEnd :: (a -> b) -> r a b

-- Base case: when we're done adding functions, return the composed function
instance CompChain (->) where
  compEnd = id

-- Recursive case: adding a new function extends the chain
instance (CompChain r) => CompChain ((x -> a) -> r x b) where
  compEnd f = \g -> compEnd (f . g)

-- Our main `comp` function starts the chain
comp :: CompChain r => (a -> b) -> r a b
comp = compEnd

-- Your example functions translated to Haskell
inc :: Num a => a -> a
inc = (+1)

sqr :: Num a => a -> a
sqr x = x * x

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

Now we can use it exactly like your JavaScript example (just without the .run):

-- Equivalent to comp(repeatStr("*"))(inc)(sqr).run(2)
comp (repeatStr "*") inc sqr 2  -- Returns "*****"

-- Equivalent to comp(repeatStr("*"))(inc)(inc)(inc)(inc)(inc).run(0)
comp (repeatStr "*") inc inc inc inc inc 0  -- Returns "*****"

2. Explicit Comp Type with run Method

If you want to mirror JavaScript's .run syntax more closely, we can wrap the function chain in a newtype with a run method:

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

-- Operator to add a function to the chain (mirrors JavaScript's function call)
infixl 1 <@>
(<@>) :: Comp a b -> (x -> a) -> Comp x b
Comp f <@> g = Comp (f . g)

-- Start the chain with the first function
comp :: (a -> b) -> Comp a b
comp = Comp

Usage mirrors your JavaScript code almost exactly:

-- Equivalent to comp(repeatStr("*"))(inc)(sqr).run(2)
comp (repeatStr "*") <@> inc <@> sqr `run` 2  -- Returns "*****"

Understanding the Type of comp

In the first approach, comp has the type:

comp :: CompChain r => (a -> b) -> r a b

This type is incredibly flexible—it adapts to the number of functions you pass. For example:

  • comp (repeatStr "*") has type CompChain r => (Int -> String) -> r Int String (waiting for a function that takes some input and returns an Int).
  • After adding inc, comp (repeatStr "*") inc has type CompChain r => (Num a => a -> Int) -> r a String.
  • After adding sqr, it becomes Num a => a -> String—a concrete function ready to take an input.

Haskell's type class resolution handles all the type matching automatically, ensuring that each function in the chain is compatible with the next.

Why This Works (No Heterogeneous Arrays Needed)

Instead of storing functions in a heterogeneous array, we're composing them directly using (.) (Haskell's function composition operator). Each composition step creates a new function with a type that reflects the entire chain, so the compiler can verify type safety at every step—no runtime checks required.

内容的提问来源于stack exchange,提问作者Aadit M Shah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:49:05