对于从另一个Iso构建Iso感到困惑

时间:2016-05-28 06:00:07

标签: haskell lens

我目前正在编写一些代码以特定方式处理逻辑表单。为了实现这一目标,我编写了以下代码,使用了镜头:

string input = "word1 abcdkl word2";
Regex regex = new Regex(@"^(?=.*\bword1\b)(?=.*\bword2\b).*$");

Match match = regex.Match(input);

if (match.Success)
{
    Console.WriteLine(match.Groups[0].Value);   
}

然后,我尝试用自然的方式写下以下内容(我相信的是):

{-# LANGUAGE NoImplicitPrelude #-}            
{-# LANGUAGE Rank2Types #-} 

module Logic.Internal.Formula where 

import BasicPrelude hiding (empty, negate)        
import qualified Data.Set as Set 
import Control.Lens 

data Atom = Pos { i :: Integer}                                                                                           
          | Neg { i :: Integer}                                                                                           
          deriving (Eq, Ord, Show, Read)                                                                                  

negatingAtom :: Iso' Atom Atom                                                                                            
negatingAtom = iso go go                                                                                                  
  where go (Pos x) = Neg x                                                                                                
        go (Neg x) = Pos x                                                                                                

newtype Conjunction a = Conjunction (Set a)                                                                               
  deriving (Eq, Ord, Read, Show)                                                                                          

conjuncts :: Conjunction a -> [a]                                                                                         
conjuncts (Conjunction x) = Set.toList x                                                                                  

newtype Disjunction a = Disjunction (Set a)                                                                               
  deriving (Eq, Ord, Read, Show)
disjuncts :: Disjunction a -> [a]                                                                                         
disjuncts (Disjunction x) = Set.toList x                                                                                  

negatingClause :: Iso' (Conjunction Atom) (Disjunction Atom)                                                              
negatingClause = liftClause negatingAtom                                                                                  

type CNF = Conjunction (Disjunction Atom)                                                                                 
type DNF = Disjunction (Conjunction Atom)

-- Helper stuff                                                               

liftClause :: (Ord a) => Iso' a a -> Iso' (Conjunction a) (Disjunction a)                                                 
liftClause x = let pipeline = Set.fromList . fmap (view x) in                                                             
  iso (Disjunction . pipeline . conjuncts) (Conjunction . pipeline . disjuncts)

然而,类型检查员肯定对此并不满意,而且我完全不确定为什么。确切的输出如下:

type CNF = Conjunction (Disjunction Atom)                                                                                 
type DNF = Disjunction (Conjunction Atom)                                                                                 

negatingForm :: Iso' CNF DNF                                                                                              
negatingForm = liftClause negatingClause

我对镜头有点新意,并且非常想了解我在这里误解的内容,以及如何实现所需的Couldn't match type ‘Conjunction Atom’ with ‘Disjunction Atom’ Expected type: p1 (Disjunction Atom) (f1 (Disjunction Atom)) -> p1 (Disjunction Atom) (f1 (Disjunction Atom)) Actual type: p1 (Disjunction Atom) (f1 (Disjunction Atom)) -> p1 (Conjunction Atom) (f1 (Conjunction Atom)) In the first argument of ‘liftClause’, namely ‘negatingClause’ In the expression: liftClause negatingClause

3 个答案:

答案 0 :(得分:2)

(答案也张贴到http://lpaste.net/164691

以下是使用TypeFamilies的解决方案。

首先,我们将简化设置:

 {-# LANGUAGE TypeFamilies #-}

 import Control.Lens

 data Atom = Pos Int | Neg Int deriving (Show)
 newtype And a = And [a]       deriving (Show)
 newtype Or a  = Or [a]        deriving (Show)

目标是创建以下功能序列:

f0 :: Atom -> Atom                      g0 :: Atom -> Atom
f1 :: And Atom -> Or Atom               g1 :: Or Atom -> And Atom
f2 :: And (Or Atom) -> Or (And Atom)    g1 :: Or (And Atom) -> And (Or Atom)
...

f和g是彼此的反转。从这些功能我们可以 制作Iso'镜头:

iso0 = iso f0 g0  :: Iso' Atom Atom
iso1 = iso f1 g1  :: Iso' (And Atom) (Or Atom)
iso2 = iso f2 g2  :: Iso' (And (Or Atom)) (Or (And Atom))

我们首先创建充当类型函数的类型族NegatedNegated a是f函数(或g函数)将a映射到的类型。

 type family Negated a

 type instance Negated Atom = Atom
 type instance Negated (And a) = Or (Negated a)
 type instance Negated (Or a) = And (Negated a)

例如,Negated (And (Or Atom))Or (And Atom))类型。

接下来,我们定义一个类型类来执行反转操作:

 class Invertible a where
   invert :: a -> Negated a

 instance Invertible Atom where
   invert (Pos a) = Neg a
   invert (Neg a) = Pos a

 instance Invertible a => Invertible (And a) where
   invert (And clauses) =  Or (map invert clauses)

 instance Invertible a => Invertible (Or a) where
   invert (Or clauses) = And (map invert clauses)

同构的定义现在是微不足道的:

 iso0 :: Iso' Atom Atom
 iso0 = iso invert invert

 iso1  :: Iso' (And Atom) (Or Atom)
 iso1 = iso invert invert

 iso2 :: Iso' (And (Or Atom)) (Or (And Atom))
 iso2 = iso invert invert

示例:

 and1 = And [ Pos 1, Neg 2, Pos 3 ]
 or1 = Or [and1]

 test1 = invert and1                 -- Or [Neg 1,Pos 2,Neg 3]
 test2 = invert or1                  -- And [Or [Neg 1,Pos 2,Neg 3]]

请注意,此方法对逻辑谓词建模的一个限制是所有Atom必须在表达式树中处于相同的深度。 例如,您无法代表此树(此处为xyz为原子):

             and
            /   \
           x    or
               /  \
              y    z

答案 1 :(得分:1)

liftClause只能在Iso' a a上运行 - 即两个域必须具有相同的类型 - 类型a

但是negatingClause的类型为:

negatingClause :: Iso' (Conjunction Atom) (Disjunction Atom)

所以由于liftClauseConjunction Atom不一样,因此您无法致电Disjunction Atom

答案 2 :(得分:1)

我没有详细阅读这一点来弄清楚你应该做什么,但是liftClause需要Iso' a a,即从某种类型到自身的同构。 negatingClauseIso' (Conjunction Atom) (Disjunction Atom);这肯定与Iso' a a不符。这就是为什么类型错误抱怨无法将Conjunction AtomDisjunction Atom匹配。