繁体   English   中英

扩展 GADT 示例 - 无法推断

[英]Extending GADTs examples - could not deduce

我正在尝试围绕评估Value扩展经典的 GADT 示例,但我遇到了一些我不完全理解的东西。

data Command a where
    Base64_     :: Command a
    Take_       :: Int -> Command a

-- eval only works with this definition
-- with this uncommented, cmd breaks with:
--
-- Could not deduce: v ~ T.Text
--  from the context: a ~ T.Text
--    bound by a pattern with constructor:
--               VString :: T.Text -> Value T.Text,
--             in an equation for ‘cmd’
-- ‘v’ is a rigid type variable bound by
--    the type signature for:
--      cmd :: forall c a v. Command c -> Value a -> Value v
data Value v where
    VString     :: T.Text -> Value T.Text
    VInt        :: Int -> Value Int
    VBool       :: Bool -> Value Bool
    VNot        :: Value Bool -> Value Bool

-- cmd only works with this definition
-- with this uncommented, eval breaks with:
-- 
-- Couldn't match expected type ‘a’ with actual type ‘T.Text’
--  ‘a’ is a rigid type variable bound by
--    the type signature for:
--       eval :: forall a. Value a -> a
-- data Value v where
--     VString     :: T.Text -> Value v
--     VInt        :: Int -> Value v
--     VBool       :: Bool -> Value v
--     VNot        :: Value Bool -> Value v

eval :: Value a -> a
eval (VString i)      = i
eval (VInt i)         = i
eval (VBool b)        = b
eval (VNot b)         = not $ eval b

cmd :: Command c -> Value a -> Value v
cmd Base64_ (VString s)         = VString $ encodeBase64 s
cmd (_) (_)                     = VInt 3 -- or show error for no match.

我正在尝试做的事情可能吗? 是否有一个 GADT 定义可以同时与evalcmd ,还是我得到的 function 签名之一不正确?

类型签名:

cmd :: Command c -> Value a -> Value v

表示任何“类型” cCommand c采用任何“类型” aValue a ,并且可以产生任何调用者请求的“类型” v Value v 但是,您的Base64_命令不采用任何类型的Value a ,它只采用Value T.Text ,并且它不产生调用者想要的任何类型的Value v ,它只产生一个Value T.Text

您可能想要做的是构建您的Command c GADT 以便c部分确定允许的输入a和实际 output v

一种方法是使用具有多种类型 arguments 的 GADT,例如:

data Command a v where
    Base64_     :: Command T.Text T.Text
    IsZero_     :: Command Int Bool

其中a表示输入类型, v表示每个定义命令的 output 类型。

现在,签名:

cmd :: Command a v -> Value a -> Value v

表达了这样的想法,即对于av的具体值的特定类型的Command av可以预期接受Value a并产生Value v ,并且以下定义将起作用:

cmd :: Command a v -> Value a -> Value v
cmd Base64_ (VString s)         = VString $ encodeBase64 s
cmd IsZero_ (VInt x)            = VBool $ x == 0

完整示例:

{-# LANGUAGE GADTs #-}

import qualified Data.Text as T
import Data.Text.Encoding.Base64

data Command a v where
    Base64_     :: Command T.Text T.Text
    IsZero_     :: Command Int Bool

data Value v where
    VString     :: T.Text -> Value T.Text
    VInt        :: Int -> Value Int
    VBool       :: Bool -> Value Bool
    VNot        :: Value Bool -> Value Bool

eval :: Value a -> a
eval (VString i)      = i
eval (VInt i)         = i
eval (VBool b)        = b
eval (VNot b)         = not $ eval b

cmd :: Command a v -> Value a -> Value v
cmd Base64_ (VString s)         = VString $ encodeBase64 s
cmd IsZero_ (VInt x)            = VBool $ x == 0

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM