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中:打印它 *主>
答案 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
一个函数。