首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Haskell中的换能器与单态约束

Haskell中的换能器与单态约束
EN

Stack Overflow用户
提问于 2015-01-11 14:00:23
回答 1查看 332关注 0票数 6

我在Haskell实现了如下换能器:

代码语言:javascript
复制
{-# LANGUAGE RankNTypes #-}

import Prelude hiding (foldr)
import Data.Foldable

type Reducer b a = a -> b -> b
type Transducer a b = forall t. Reducer t b -> Reducer t a

class Foldable c => Collection c where
    insert :: a -> c a -> c a
    empty  :: c a

reduce :: Collection c => Transducer a b -> c a -> c b
reduce f = foldr (f insert) empty

mapping :: (a -> b) -> Transducer a b
mapping f g x = g (f x)

现在,我想定义一个通用的map函数。因此,我将上述代码加载到GHCi中:

代码语言:javascript
复制
Prelude> :load Transducer
[1 of 1] Compiling Main             ( Transducer.hs, interpreted )
Ok, modules loaded: Main.
*Main> let map = reduce . mapping

<interactive>:3:20:
    Couldn't match type ‘Reducer t0 b1 -> Reducer t0 a1’
                  with ‘forall t. Reducer t b -> Reducer t a’
    Expected type: (a1 -> b1) -> Transducer a b
      Actual type: (a1 -> b1) -> Reducer t0 b1 -> Reducer t0 a1
    Relevant bindings include
      map :: (a1 -> b1) -> c a -> c b (bound at <interactive>:3:5)
    In the second argument of ‘(.)’, namely ‘mapping’
    In the expression: reduce . mapping
*Main> let map f = reduce (mapping f)
*Main> :t map
map :: Collection c => (a -> b) -> c a -> c b

所以我不能定义map = reduce . mapping。但是,我可以定义map f = reduce (mapping f)

我认为这个问题是由单态限制引起的。我真的很想写map = reduce . mapping而不是map f = reduce (mapping f)。因此,我有两个问题:

  1. 是什么导致了这个问题?这真的是单形限制吗?
  2. 我该如何解决这个问题?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-01-12 10:04:58

如果您将Transducer设置为newtype,则GHC将比GHC更好地处理这些类型。存在型变量不会脱离作用域-传感器将保持多态。

换句话说,在下面的定义中,map = reduce . mapping工作

代码语言:javascript
复制
{-# LANGUAGE RankNTypes #-}

import Prelude hiding (foldr, map, (.), id)
import Control.Category
import Data.Foldable

type Reducer b a = a -> b -> b
newtype Transducer a b = MkTrans { unTrans :: forall t. Reducer t b -> Reducer t a }

class Foldable c => Collection c where
    insert :: a -> c a -> c a
    empty  :: c a

instance Collection [] where
  insert = (:)
  empty = []

reduce :: Collection c => Transducer a b -> c a -> c b
reduce f = foldr (unTrans f insert) empty

mapping :: (a -> b) -> Transducer a b
mapping f = MkTrans $ \g x -> g (f x)

filtering :: (a -> Bool) -> Transducer a a
filtering f = MkTrans $ \g x y -> if f x then g x y else y

map :: Collection c => (a -> b) -> c a -> c b
map = reduce . mapping

filter :: Collection c => (a -> Bool) -> c a -> c a
filter = reduce . filtering

instance Category Transducer where
  id = MkTrans id
  MkTrans f . MkTrans g = MkTrans $ \x -> g (f x)

dub :: Num a => a -> a
dub x = x + x

test1 :: [Int]
test1 = reduce (filtering even . mapping dub) [1..10]
-- [2,4,6,8,10,12,14,16,18,20]

test2 :: [Int]
test2 = reduce (mapping dub . filtering even) [1..10]
-- [4,8,12,16,20]

代码语言:javascript
复制
*Main> :t reduce . mapping
reduce . mapping :: Collection c => (a -> b) -> c a -> c b

此外,您还可以检查lenses/,其中的定义是type Transducer a b =:: (a -> Constant (Endo x) a) -> (b -> Constant (Endo x) b)和其他各种。还有其他有趣的讨论。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27887907

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档