尝试创建一个将另一个函数映射到函数列表的函数

时间:2015-04-13 16:20:50

标签: haskell

compose :: [(u -> t)] -> ((u -> t) -> (u->y)) -> [(u->y)] 
compose [] _ = []
compose l f = map f l

我试图创建一个接收函数列表的函数,并在该列表的元素上映射另一个函数。

实施例: 撰写[(+2),(+ 3)](+1)= [(+ 3),(+ 4)]

这是我尝试运行此代码时控制台显示的消息

*主> (撰写[(+2)](+1))

:77:2:     使用'print'时没有(Show(t0 - > t0))的实例     在交互式GHCi命令的stmt中:打印它 *主>

1 个答案:

答案 0 :(得分:6)

没有一种方法可以智能地将函数转换为字符串,这就是您在此处看到的错误消息。函数没有Show实例,您需要一个Show实例来查看GHCi中的输出。当您在Haskell中创建函数时,编译器将其转换为低级命令,您不必将原始函数定义保留在元数据或任何内容中。您将无法看到(+1) . (+2)成为(+3),它就不是Haskell功能如何运作。

相反,您可以将其指定为名称:

> let fs = compose [(+2)] (+1)

然后对其应用值

> map ($ 10) fs
[13]

如果您希望能够将(+2)(+1)之类的内容转换为(+3),则需要创建自己的数据类型。这意味着除非您定义非常通用的行为,否则您可以表示的功能受到严重限制。对于Int上的简单函数,您可以执行

data ArithFunc
    = Add Int
    | Subtract Int
    | Multiply Int
    | ModBy Int
    | Abs
    | Negate
    | Compose ArithFunc ArithFunc
    deriving (Eq, Show)

然后你可以写一个自定义的撰写运算符:

toFunction :: ArithFunc -> (Int -> Int)
toFunction (Add x) = (+x)
toFunction (Subtract x) = subtract x
toFunction (Multiply x) = (*x)
toFunction (ModBy x) = (`mod` x)
toFunction Abs = abs
toFunction Negate = negate
toFunction (Compose f1 f2) = toFunction f1 . toFunction f2

infixr 9 #
(#) :: ArithFunc -> ArithFunc -> ArithFunc
f1 # f2 = simplify $ Compose f1 f2

infixr 0 $$
($$) :: ArithFunc -> Int -> Int
f $$ x = toFunction f x

simplify (Compose (Add x) (Add y)) = Add (x + y)
simplify (Compose (Add x) (Subtract y)) = Add (x - y)
-- Continue adding simplification rules as desired

compose :: [ArithFunc] -> (ArithFunc -> ArithFunc) -> [ArithFunc]
compose l f = map (simplify . f) l

然后你可以写

> compose [Add 2] (Add 1)
[Add 3]
> map ($$ 10) $ compose [Add 2] (Add 1)
[13]

这个解决方案已经接近完成,你真的需要以这样的方式定义simplify,它继续简化嵌套的Compose构造,直到没有做出改变,需要有更多的简化规则,可以表示其他操作,导致需要更多的简化规则,等等。上面的所有这些工作只是在Int s上使用一组有限的数值计算来做这类事情,想象一下扩展它适用于所有类型。这就是为什么Haskell选择一种更简单的存储函数定义的路径,而不是字面意思,以及为什么你可以show一个函数。