ap-reflect
debug
simple-reflect と組み合わせて使う
モチベーション
simple-reflect
パッケージでは、演算子を以下のように定義している。
iOp :: (Expr -> Expr) -> (Integer -> Integer) -> Expr -> Expr
dOp :: (Expr -> Expr) -> (Double -> Double) -> Expr -> Expr
bOp :: (Expr -> Expr) -> (Bool -> Bool) -> Expr -> Expr
iOp r f a = (r a) { intExpr = f <$> intExpr a }
dOp r f a = (r a) { doubleExpr = f <$> doubleExpr a }
bOp r f a = (r a) { boolExpr = f <$> boolExpr a }
iOp2 :: (Expr -> Expr -> Expr) -> (Integer -> Integer -> Integer) -> Expr -> Expr -> Expr
dOp2 :: (Expr -> Expr -> Expr) -> (Double -> Double -> Double) -> Expr -> Expr -> Expr
bOp2 :: (Expr -> Expr -> Expr) -> (Bool -> Bool -> Bool) -> Expr -> Expr -> Expr
iOp2 r f a b = (r a b) { intExpr = f <$> intExpr a <*> intExpr b }
dOp2 r f a b = (r a b) { doubleExpr = f <$> doubleExpr a <*> doubleExpr b }
bOp2 r f a b = (r a b) { boolExpr = f <$> boolExpr a <*> boolExpr b }
また、Expr
型の定義は以下のようになっている。
data Expr = Expr
{ showExpr :: Int -> ShowS -- ^ Show with the given precedence level
, intExpr :: Maybe Integer -- ^ Integer value?
, doubleExpr :: Maybe Double -- ^ Floating value?
, boolExpr :: Maybe Bool
, reduced :: Maybe Expr -- ^ Next reduction step
}
これらを一般化して、任意の型に対して動作する関数が makeBinOp 。
使い方
λ stack repl --package simple-reflect --package ap-reflect
*Main> mapM_ print . reductions $ makeBinOp "+" (+) -$- Just a -*- Just b
(+) <$> Just a <*> Just b
Just (a +) <*> Just b
Just (a + b)
サンプル
{-# LANGUAGE TypeOperators #-}
import Control.Applicative
import Data.Functor.Identity
import Debug.SimpleReflect
import Debug.Reflect
-- внутреннее представление операций
-- (+)
(.+) :: (Num a, Show a) => a ~> a ~> a
(.+) = makeBinOp "+" (+)
-- (-)
(.-) :: (Num a, Show a) => a ~> a ~> a
(.-) = makeBinOp "-" (-)
-- (*)
(.*) :: (Num a, Show a) => a ~> a ~> a
(.*) = makeBinOp "*" (*)
-- (/)
(./) :: (Fractional a, Show a) => a ~> a ~> a
(./) = makeBinOp "/" (/)
-- (++)
(.++) :: (Show a) => [a] ~> [a] ~> [a]
(.++) = makeBinOp "++" (++)
-- (:)
(.:) :: (Show a) => a ~> [a] ~> [a]
(.:) = makeBinOp ":" (:)
sequenceA' :: (Show a, Show (f a), Show (f [a]), Show (f ([a] ~> [a])), Applicative f) => [f a] -> Ap (f [a])
sequenceA' [] = pure'' []
sequenceA' (x:xs) = Val ap' :$ ((.:) -$- x) :$ sequenceA' xs
traverse' :: (Show a, Show b, Show (f b), Show (f [b]), Show (f ([b] ~> [b])), Applicative f) => (a -> f b) -> [a] -> Ap (f [b])
traverse' _ [] = pure'' []
traverse' f (x:xs) = Val ap' :$ (Val fmap' :$ Val (.:) :$ fx) :$ traverse' f xs
where fx = Val (Fn "f" f) :$ Val x
main :: IO ()
main = do
let line = putStrLn "------------------------------------------"
let
g' = makeBinOp "g" (g :: Expr -> Expr -> Expr)
h' = makeBinOp "h" (h :: Expr -> Expr -> Expr)
mapM_ print . reductions $ Val [fromFn g' 1, fromFn h' 2] -*- [a, b, c]
line
mapM_ print . reductions $ makeBinOp "f" (f :: Expr -> Expr -> Expr) -$- Just a -*- Just b
line
mapM_ print . reductions $ Val (Just (fromFn (.+) a)) -*- Just b
line
mapM_ print . reductions $ Val (Just (Fn "(+ a)" (+ a))) -*- Just b
line
mapM_ print . reductions $ fmap'' (.+) (Just a)
line
mapM_ print . reductions $ fmap'' (.+) (Just a) -*- Just b
line
mapM_ print . reductions $ pure'' (.+) -*- Just a -*- Just b
line
mapM_ print . reductions $ (.+) -$- Identity a
line
mapM_ print . reductions $ (.+) -$- Identity a -*- Identity b
line
mapM_ print . reductions $ (.+) -$- Const (a + b)
line
mapM_ print . reductions $ (.+) -$- Const a -*- Const b
line
mapM_ print . reductions $ (.+) -$- ZipList [1,2,3] -*- ZipList [100,100,100]
line
mapM_ print . reductions $ makeBinOp "max" max -$- ZipList [1,2,3,4,5,3] -*- ZipList [5,3,1,2]
line
mapM_ print . reductions $ Val (ZipList [fromFn (.+) 1, fromFn (.*) 100]) -*- ZipList [a,b]
line
let f x = if even (length x) then Just (head x) else Nothing
mapM_ print . reductions $ traverse' f ["ab","cdef","gh"]
line
mapM_ print . reductions $ sequenceA' [Just a, Just b, Just c]
line
mapM_ print . reductions $ sequenceA' [Just a, Nothing, Just c]
line
mapM_ print . reductions $ makeBinOp "f" (+) -$- [x, y]
line
mapM_ print . reductions $ (.++) -$- Just "hello " -*- Just "world"
line
mapM_ print . reductions $ (.+) -$- ("1 + ", 1) -*- ("6 =", 6)
line
mapM_ print . reductions $ (.*) -$- Just 3 -*- Just 2
line
mapM_ print . reductions $ (./) -$- Just 3 -*- Just 2
line
mapM_ print . reductions $ (.+) -$- Just 1
line
mapM_ print . reductions $ (.+) -$- Just 1 -*- Just 3
line
mapM_ print . reductions $ (.+) -$- Just a -*- Just b
line
mapM_ print . reductions $ (.-) -$- Just a -*- Just b
line
mapM_ print . reductions $ (.+) -$- Nothing
line
mapM_ print . reductions $ (.+) -$- Just a -*- Nothing
line
mapM_ print . reductions $ (.+) -$- Nothing -*- Just b
line
mapM_ print . reductions $ (.+) -$- [1, 2, 3]
line
mapM_ print . reductions $ (.+) -$- [a, b] -*- [x, y]
line
mapM_ print . reductions $ (.+) -$- []
line
mapM_ print . reductions $ (.+) -$- [1,2] -*- []
line
mapM_ print . reductions $ (.+) -$- Right a -*- Left b
line
mapM_ print . reductions $ (.+) -$- Left a -*- Right b
line
λ stack repl --package simple-reflect --package ap-reflect Sample.hs
*Main> main
[(g 1),(h 2)] <*> [a,b,c]
[g 1 a,g 1 b,g 1 c,h 2 a,h 2 b,h 2 c]
------------------------------------------
f <$> Just a <*> Just b
Just (f a) <*> Just b
Just (f a b)
------------------------------------------
Just (a +) <*> Just b
Just (a + b)
------------------------------------------
Just (+ a) <*> Just b
Just (b + a)
------------------------------------------
fmap (+) (Just a)
Just (a +)
------------------------------------------
fmap (+) (Just a) <*> Just b
Just (a +) <*> Just b
Just (a + b)
------------------------------------------
pure (+) <*> Just a <*> Just b
Just (+) <*> Just a <*> Just b
Just (a +) <*> Just b
Just (a + b)
------------------------------------------
(+) <$> Identity a
Identity (a +)
------------------------------------------
(+) <$> Identity a <*> Identity b
Identity (a +) <*> Identity b
Identity (a + b)
------------------------------------------
(+) <$> Const (a + b)
Const (a + b)
------------------------------------------
(+) <$> Const a <*> Const b
Const a <*> Const b
Const (a <> b)
------------------------------------------
(+) <$> ZipList {getZipList = [1,2,3]} <*> ZipList {getZipList = [100,100,100]}
ZipList {getZipList = [(1 +),(2 +),(3 +)]} <*> ZipList {getZipList = [100,100,100]}
ZipList {getZipList = [101,102,103]}
------------------------------------------
max <$> ZipList {getZipList = [1,2,3,4,5,3]} <*> ZipList {getZipList = [5,3,1,2]}
ZipList {getZipList = [(max 1),(max 2),(max 3),(max 4),(max 5),(max 3)]} <*> ZipList {getZipList = [5,3,1,2]}
ZipList {getZipList = [5,3,3,4]}
------------------------------------------
ZipList {getZipList = [(1 +),(100 *)]} <*> ZipList {getZipList = [a,b]}
ZipList {getZipList = [1 + a,100 * b]}
------------------------------------------
(:) <$> f "ab" <*> ((:) <$> f "cdef" <*> ((:) <$> f "gh" <*> pure ""))
(:) <$> Just 'a' <*> ((:) <$> f "cdef" <*> ((:) <$> f "gh" <*> pure ""))
Just ('a' :) <*> ((:) <$> f "cdef" <*> ((:) <$> f "gh" <*> pure ""))
Just ('a' :) <*> ((:) <$> Just 'c' <*> ((:) <$> f "gh" <*> pure ""))
Just ('a' :) <*> (Just ('c' :) <*> ((:) <$> f "gh" <*> pure ""))
Just ('a' :) <*> (Just ('c' :) <*> ((:) <$> Just 'g' <*> pure ""))
Just ('a' :) <*> (Just ('c' :) <*> (Just ('g' :) <*> pure ""))
Just ('a' :) <*> (Just ('c' :) <*> (Just ('g' :) <*> Just ""))
Just ('a' :) <*> (Just ('c' :) <*> Just "g")
Just ('a' :) <*> Just "cg"
Just "acg"
------------------------------------------
(:) <$> Just a <*> ((:) <$> Just b <*> ((:) <$> Just c <*> pure []))
Just (a :) <*> ((:) <$> Just b <*> ((:) <$> Just c <*> pure []))
Just (a :) <*> (Just (b :) <*> ((:) <$> Just c <*> pure []))
Just (a :) <*> (Just (b :) <*> (Just (c :) <*> pure []))
Just (a :) <*> (Just (b :) <*> (Just (c :) <*> Just []))
Just (a :) <*> (Just (b :) <*> Just [c])
Just (a :) <*> Just [b,c]
Just [a,b,c]
------------------------------------------
(:) <$> Just a <*> ((:) <$> Nothing <*> ((:) <$> Just c <*> pure []))
Just (a :) <*> ((:) <$> Nothing <*> ((:) <$> Just c <*> pure []))
Just (a :) <*> (Nothing <*> ((:) <$> Just c <*> pure []))
Just (a :) <*> (Nothing <*> (Just (c :) <*> pure []))
Just (a :) <*> (Nothing <*> (Just (c :) <*> Just []))
Just (a :) <*> (Nothing <*> Just [c])
Just (a :) <*> Nothing
Nothing
------------------------------------------
f <$> [x,y]
[(f x),(f y)]
------------------------------------------
(++) <$> Just "hello " <*> Just "world"
Just ("hello " ++) <*> Just "world"
Just "hello world"
------------------------------------------
(+) <$> ("1 + ",1) <*> ("6 =",6)
("1 + ",(1 +)) <*> ("6 =",6)
("1 + 6 =",7)
------------------------------------------
(*) <$> Just 3 <*> Just 2
Just (3 *) <*> Just 2
Just 6
------------------------------------------
(/) <$> Just 3.0 <*> Just 2.0
Just (3.0 /) <*> Just 2.0
Just 1.5
------------------------------------------
(+) <$> Just 1
Just (1 +)
------------------------------------------
(+) <$> Just 1 <*> Just 3
Just (1 +) <*> Just 3
Just 4
------------------------------------------
(+) <$> Just a <*> Just b
Just (a +) <*> Just b
Just (a + b)
------------------------------------------
(-) <$> Just a <*> Just b
Just (a -) <*> Just b
Just (a - b)
------------------------------------------
(+) <$> Nothing
Nothing
------------------------------------------
(+) <$> Just a <*> Nothing
Just (a +) <*> Nothing
Nothing
------------------------------------------
(+) <$> Nothing <*> Just b
Nothing <*> Just b
Nothing
------------------------------------------
(+) <$> [1,2,3]
[(1 +),(2 +),(3 +)]
------------------------------------------
(+) <$> [a,b] <*> [x,y]
[(a +),(b +)] <*> [x,y]
[a + x,a + y,b + x,b + y]
------------------------------------------
(+) <$> []
[]
------------------------------------------
(+) <$> [1,2] <*> []
[(1 +),(2 +)] <*> []
[]
------------------------------------------
(+) <$> Right a <*> Left b
Right (a +) <*> Left b
Left b
------------------------------------------
(+) <$> Left a <*> Right b
Left a <*> Right b
Left a
------------------------------------------
問題点
True && Fales && True
のような式を書く場合に、どうしたら良いかわからない。
ghci
*Main> and = makeBinOp "&&" (&&)
*Main> :t and
and :: Bool ~> (Bool ~> Bool)
*Main> and -$- (Just True) -*- (Just True)
(&&) <$> Just True <*> Just True
*Main> and -$- e1 -*- Just False
<interactive>:10:9: error:
• Couldn't match type ‘Maybe Bool’ with ‘Bool’
Expected type: Ap Bool
Actual type: Ap (Maybe Bool)
• In the second argument of ‘(-$-)’, namely ‘e1’
In the first argument of ‘(-*-)’, namely ‘and -$- e1’
In the expression: and -$- e1 -*- Just False
<interactive>:10:16: error:
• Couldn't match type ‘Maybe’ with ‘Ap’
Expected type: Ap Bool
Actual type: Maybe Bool
• In the second argument of ‘(-*-)’, namely ‘Just False’
In the expression: and -$- e1 -*- Just False
In an equation for ‘it’: it = and -$- e1 -*- Just False
通常の Applicative であれば以下のように計算できる
ghci
*Main> (&&) <$> Just True <*> Just True
Just True
*Main> e1 = (&&) <$> Just True <*> Just True
*Main> (&&) <$> e1 <*> Just False
Just False
これは、計算の結果 Ap
になってしまうために起きている問題。
ghci
*Main> :t (&&) <$> Just True <*> Just True
(&&) <$> Just True <*> Just True :: Maybe Bool
*Main> :t and -$- (Just True) -*- (Just True)
and -$- (Just True) -*- (Just True) :: Ap (Maybe Bool)
Last updated