【发布时间】:2018-11-18 13:37:44
【问题描述】:
我是 Haskell 的初学者,所以请放纵一下。由于这里不重要的原因,我试图定义一个运算符<^>,它接受一个函数和一个参数,并通过参数返回函数的值,无论哪个函数和参数先出现。简而言之,我希望能够写出以下内容:
foo :: Int -> Int
foo x = x * x
arg :: Int
arg = 2
foo <^> arg -- valid, returns 4
arg <^> foo -- valid, returns 4
我试图通过类型族来实现这一点,如下所示:
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeFamilies, TypeOperators #-}
class Combine t1 t2 where
type Output t1 t2 :: *
(<^>) :: t1 -> t2 -> Output t1 t2
instance Combine (a->b) a where
type Output (a->b) a = b
f <^> x = f x
instance Combine a (a->b) where
type Output a a->b = b
x <^> f = f x
在此代码中,GHC 抛出 Conflicting family instance declarations。我的猜测是,当 a->b 类型和 a 类型相同时,GHC 抱怨的重叠就会发生。我不太了解 Haskell,但我怀疑使用递归类型定义,可能能够构建这种情况。我有几个问题:
- 由于这是一个相当遥远的场景,在我的应用程序中永远不会发生(尤其是上面的 foo 和 arg 不会出现),我想知道是否有办法指定一个虚拟默认实例以在重叠的情况下使用?我尝试了不同的
OVERLAPS和OVERLAPPING标志,但它们没有任何效果。 - 如果没有,有没有更好的方法来实现我想要的?
谢谢!
【问题讨论】:
-
我认为你的课没有意义。
const id和id const都是有效代码,那么const <^> id会做什么? -
写下你的“不重要的原因”,这里有一个严重的用例:有些人想使用
(.)运算符来应用后缀函数,就像在大多数 OOP 中一样。但是有太多的遗留代码使用它作为 compose。通过查看(.)的参数类型,我们可以同时做到这两点吗?还有const.id的问题。
标签: haskell