用Haskell表示交换半群多项式
我试图表达如下术语:用Haskell表示交换半群多项式,haskell,symbolic-math,algebra,Haskell,Symbolic Math,Algebra,我试图表达如下术语: a0 <> a1 <> ... <> an-1 newtype SemigroupPolynomial a = SP Map a Integer 其中,映射包含多项式的不同项及其计数 这样,我们就可以表示和 3 + 3 + 6 as(假设重载列表): 但我们也可以表示以下术语: 3 * 3 * 6 半群多项式可以是半群的一个实例: instance ??? a => Semigroup (SemigroupPolynomia
a0 <> a1 <> ... <> an-1
newtype SemigroupPolynomial a = SP Map a Integer
其中,映射包含多项式的不同项及其计数
这样,我们就可以表示和
3 + 3 + 6
as(假设重载列表):
但我们也可以表示以下术语:
3 * 3 * 6
半群多项式
可以是半群
的一个实例:
instance ??? a => Semigroup (SemigroupPolynomial a) where
(MP p0) <> (MP p1) =
MP $ Map.filter (0/=) $ Map.unionWith (+) p0 p1
实例???a=>半群(半群多项式a),其中
(MP p0)(MP p1)=
MP$Map.filter(0/=)$Map.union带(+)p0 p1
否问题是我必须在?
中设置哪些约束,以便:
操作是可交换和关联的关于如何表示交换幺半群的类似问题。然而,似乎约束
(阿贝尔m,幺半群m)
可能太强了(我不需要零元素),这将阻止我使用它来表示产品。正如@LeftRoundout所评论的,这里不需要约束。不要被“约束”这个词所愚弄。在Haskell中,约束的主要目的不是以某种方式约束特定类型或操作的行为。相反,它是将函数将接受的类型集约束为支持一组操作的类型
当我写作时:
fmapTwice :: (Functor f) => (a -> a) -> f a -> f a
fmapTwice f = fmap (f . f)
我并不是真的限制类型f
像一个函子一样工作,并遵守函子所要求的规则。相反,我将fmap两次
函数限制为仅应用于支持fmap
操作的类型f
没有什么能阻止某个混蛋写作:
data Foo a = Foo a | NoFoo deriving (Show)
instance Functor Foo where
fmap _ _ = NoFoo -- invalid functor violates: fmap id = id
并将我的函数应用于此无效函子:
> fmapTwice (*2) (Foo 10)
NoFoo
>
Haskell依靠程序员规则来确保声明为具有Functor
实例的东西是一个行为良好的Functor
在您的示例中,实例:
import Data.Semigroup
import qualified Data.Map as Map
import Data.Map.Strict (Map)
data SemigroupPolynomial a = SP (Map a Integer) deriving (Show)
instance (Ord a) => Semigroup (SemigroupPolynomial a) where
(SP p0) <> (SP p1) =
SP $ Map.filter (0/=) $ Map.unionWith (+) p0 p1
foldSP' :: (Monoid a) => SemigroupPolynomial a -> a
foldSP' (SP m) = mconcat $ concatMap (\(a, n) -> replicate (fromIntegral n) a)
(Map.assocs m)
如果您想以某种方式在数据类型中引入可交换性要求,一种方法(根本不涉及Haskell“约束”)是编写如下内容:
data CommutativeOp a = CO (a -> a -> a)
foldSP :: CommutativeOp a -> SemigroupPolynomial a -> a
foldSP (CO f) (SP m) = <same as above>
您正在声明(+)
和(*)
是交换操作,这将确保foldSP
仅适用于此类操作:
foldSP :: (a -> a -> a) -> SemigroupPolynomial a -> a
foldSP f (SP m) = foldr1 f $ concatMap (\(a, n) -> replicate (fromIntegral n) a)
(Map.assocs m)
main = do let sp = singleton 3 <> singleton 3 <> singleton 6
print sp
print $ foldSP (*) sp
print $ foldSP (+) sp
print $ foldSP (-) sp -- wrong, but it's your own damn fault
main = do let sp = singleton 3 <> singleton 3 <> singleton 6
print $ foldSP plusOp sp
print $ foldSP timesOp sp
现在fold操作将使用newtype中隐含的操作(这里,仅使用monoid实例):
也许这就是你想要的。如果是,完整示例如下所示:
import Data.Semigroup
import qualified Data.Map as Map
import Data.Map.Strict (Map)
newtype SemigroupPolynomial a = SP (Map a Integer) deriving (Show)
class Commutative a
instance Commutative (Sum a)
instance Commutative (Product a)
instance (Ord a, Commutative a) => Semigroup (SemigroupPolynomial a) where
(SP p0) <> (SP p1) =
SP $ Map.filter (0/=) $ Map.unionWith (+) p0 p1
singleton :: a -> SemigroupPolynomial a
singleton x = SP $ Map.singleton x 1
foldSP' :: (Monoid a) => SemigroupPolynomial a -> a
foldSP' (SP m) = mconcat $ concatMap (\(a, n) -> replicate (fromIntegral n) a)
(Map.assocs m)
main = do let sp1 = singleton (Sum 3) <> singleton (Sum 3) <> singleton (Sum 6)
print sp1
print (foldSP' sp1)
let sp2 = singleton (Product 3) <> singleton (Product 3)
<> singleton (Product 6)
print sp2
print (foldSP' sp2)
导入数据半群
导入符合条件的数据。映射为映射
导入Data.Map.Strict(Map)
新类型半群多项式a=SP(映射一个整数)派生(显示)
类交换a
实例交换(和a)
实例交换(乘积a)
实例(Ord a,交换a)=>半群(半群多项式a),其中
(SP p0)(SP p1)=
SP$Map.filter(0/=)$Map.union带(+)p0 p1
单例::a->半群多项式a
单例x=SP$Map.singleton x 1
foldSP':(幺半群a)=>半群多项式a->a
foldSP'(SP m)=mconcat$concatMap(\(a,n)->复制(从整数n)a)
(Map.assocs m)
main=do让sp1=singleton(Sum 3)singleton(Sum 3)singleton(Sum 6)
打印sp1
打印(foldSP的sp1)
设sp2=singleton(产品3)singleton(产品3)
单身人士(产品6)
打印sp2
打印(foldSP的sp2)
正如@LeftRoundound所评论的,这里不需要约束。不要被“约束”这个词所愚弄。在Haskell中,约束的主要目的不是以某种方式约束特定类型或操作的行为。相反,它是将函数将接受的类型集约束为支持一组操作的类型
当我写作时:
fmapTwice :: (Functor f) => (a -> a) -> f a -> f a
fmapTwice f = fmap (f . f)
我并不是真的限制类型f
像一个函子一样工作,并遵守函子所要求的规则。相反,我将fmap两次
函数限制为仅应用于支持fmap
操作的类型f
没有什么能阻止某个混蛋写作:
data Foo a = Foo a | NoFoo deriving (Show)
instance Functor Foo where
fmap _ _ = NoFoo -- invalid functor violates: fmap id = id
并将我的函数应用于此无效函子:
> fmapTwice (*2) (Foo 10)
NoFoo
>
Haskell依靠程序员规则来确保声明为具有Functor
实例的东西是一个行为良好的Functor
在您的示例中,实例:
import Data.Semigroup
import qualified Data.Map as Map
import Data.Map.Strict (Map)
data SemigroupPolynomial a = SP (Map a Integer) deriving (Show)
instance (Ord a) => Semigroup (SemigroupPolynomial a) where
(SP p0) <> (SP p1) =
SP $ Map.filter (0/=) $ Map.unionWith (+) p0 p1
foldSP' :: (Monoid a) => SemigroupPolynomial a -> a
foldSP' (SP m) = mconcat $ concatMap (\(a, n) -> replicate (fromIntegral n) a)
(Map.assocs m)
如果您想以某种方式在数据类型中引入可交换性要求,一种方法(根本不涉及Haskell“约束”)是编写如下内容:
data CommutativeOp a = CO (a -> a -> a)
foldSP :: CommutativeOp a -> SemigroupPolynomial a -> a
foldSP (CO f) (SP m) = <same as above>
您正在声明(+)
和(*)
是交换操作,这将确保foldSP
仅适用于此类操作:
foldSP :: (a -> a -> a) -> SemigroupPolynomial a -> a
foldSP f (SP m) = foldr1 f $ concatMap (\(a, n) -> replicate (fromIntegral n) a)
(Map.assocs m)
main = do let sp = singleton 3 <> singleton 3 <> singleton 6
print sp
print $ foldSP (*) sp
print $ foldSP (+) sp
print $ foldSP (-) sp -- wrong, but it's your own damn fault
main = do let sp = singleton 3 <> singleton 3 <> singleton 6
print $ foldSP plusOp sp
print $ foldSP timesOp sp
现在fold操作将使用newtype中隐含的操作(这里,仅使用monoid实例):
也许这就是你想要的。如果是,完整示例如下所示:
import Data.Semigroup
import qualified Data.Map as Map
import Data.Map.Strict (Map)
newtype SemigroupPolynomial a = SP (Map a Integer) deriving (Show)
class Commutative a
instance Commutative (Sum a)
instance Commutative (Product a)
instance (Ord a, Commutative a) => Semigroup (SemigroupPolynomial a) where
(SP p0) <> (SP p1) =
SP $ Map.filter (0/=) $ Map.unionWith (+) p0 p1
singleton :: a -> SemigroupPolynomial a
singleton x = SP $ Map.singleton x 1
foldSP' :: (Monoid a) => SemigroupPolynomial a -> a
foldSP' (SP m) = mconcat $ concatMap (\(a, n) -> replicate (fromIntegral n) a)
(Map.assocs m)
main = do let sp1 = singleton (Sum 3) <> singleton (Sum 3) <> singleton (Sum 6)
print sp1
print (foldSP' sp1)
let sp2 = singleton (Product 3) <> singleton (Product 3)
<> singleton (Product 6)
print sp2
print (foldSP' sp2)
导入数据半群
导入符合条件的数据。映射为映射
导入Data.Map.Strict(Map)
新类型半群多项式a=SP(映射一个整数)派生(显示)
类交换a
实例交换(和a)
实例交换(乘积a)
实例(Ord a,交换a)=>半群(半群多项式a),其中
(SP p0)(SP p1)=
SP$Map.filter(0/=)$Map.union带(+)p0 p1
单例::a->半群多项式a
单例x=SP$Map.singleton x 1
foldSP':(幺半群a)=>半群多项式a->a
foldSP'(SP m)=mconcat$concatMap(\(a,n)->复制(从整数n)a)
(Map.assocs m)
main=do让sp1=singleton(Sum 3)singleton(Sum 3)singleton(Sum 6)
打印sp1
打印(foldSP的sp1)
设sp2=singleton(产品3)singleton(产品3)
单身人士(产品6)
打印sp2