Я хотел бы смешать оцененные и неоцененные термины, используя программирование на уровне типов.
Я сделал простой пример, где Sum не оценивается, а Const оценивается.
Следующее работает нормально:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
module Main where
type family And a b where
And 'True 'True = 'True
And _ _ = 'False
data TermList (b::Bool) where
Nil :: TermList 'True
Cons :: Term a -> TermList b -> TermList (And a b)
instance Show (TermList b) where
show Nil = "Nil"
show (Cons a b) = "(Cons " ++ show a ++ " " ++ show b ++ ")"
data Term (b::Bool) where
Const :: Int -> Term 'True
Sum :: TermList v -> Term 'False
instance Show (Term b) where
show (Const a) = "(Const " ++ show a ++ ")"
show (Sum a) = "(Sum " ++ show a ++ ")"
class Eval e where
eval :: e -> Term 'True
instance Eval (Term 'True) where
eval = id
instance Eval (Term 'False) where
eval (Sum x) = eval x
instance Eval (TermList b) where
eval _ = Const 0
{-
instance Eval (TermList b) where
eval (Nil) = Const 0
eval (Cons x xs) = case (eval x, eval xs) of
(Const v, Const vs) -> Const (v + vs)
-}
main :: IO ()
main =
let sum1 = Sum (Cons (Const 3) (Cons (Const 4) Nil))
sum2 = Sum (Cons (Const 5) (Cons (Const 6) Nil))
sum3 = Sum (Cons sum1 (Cons sum2 Nil))
in
do
putStrLn (show sum1)
putStrLn (show sum2)
putStrLn (show sum3)
putStrLn (show (eval sum1))
putStrLn (show (eval sum2))
putStrLn (show (eval sum3))
Однако замена оценки TermList на оценку в комментариях дает:
src\Main.hs:45:30: error:
* Could not deduce (Eval (Term a)) arising from a use of `eval'
from the context: b ~ And a b1
bound by a pattern with constructor:
Cons :: forall (a :: Bool) (b :: Bool).
Term a -> TermList b -> TermList (And a b),
in an equation for `eval'
at src\Main.hs:45:11-19
* In the expression: eval x
In the expression: (eval x, eval xs)
In the expression:
case (eval x, eval xs) of { (Const v, Const vs) -> Const (v + vs) }
|
45 | eval (Cons x xs) = case (eval x, eval xs) of
| ^^^^^^
Это меня очень удивляет: надо ли запоминать типы всех составных частей?
eval
никогда не может вернуть ничего, кроме функции, которая оценивается какTerm 'True
. В вашем сопоставлении с образцом, что произойдет, еслиx
будетTermList v
? Я думаю, вы получаете противоречие, не позволяющее GHC вывести тип. - person Bob Dalgleish   schedule 21.01.2019eval
дляx
, который имеет типTerm a
(логическийa
является экзистенциальным), требуется, чтобы экземплярEval (Term a)
находился в области видимости. Но у нас есть толькоEval (Term 'True)
иEval (Term 'False)
в области видимости. - person Potato44   schedule 22.01.2019