Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell中带失败的简单型lambda演算_Haskell_Lambda_Maybe_Typed - Fatal编程技术网

Haskell中带失败的简单型lambda演算

Haskell中带失败的简单型lambda演算,haskell,lambda,maybe,typed,Haskell,Lambda,Maybe,Typed,我是哈斯克尔的新来者,如果这个问题没有太多意义,我向你道歉 我希望能够在Haskell中实现简单类型的lambda表达式,当我尝试将一个表达式应用于另一个错误类型时,结果不是类型错误,而是某个设置值,例如Nothing。起初我认为使用monad可能是正确的方法,但我一直无法让任何东西正常工作。我想知道,如果有的话,正确的方法是什么 如果有帮助的话,问题的背景是我正在进行的一个项目,它为句子中的单词指定词性标签。对于我的标记集,我使用分类语法类型;这些是类型化的lambda表达式,如(e->s)或

我是哈斯克尔的新来者,如果这个问题没有太多意义,我向你道歉

我希望能够在Haskell中实现简单类型的lambda表达式,当我尝试将一个表达式应用于另一个错误类型时,结果不是类型错误,而是某个设置值,例如Nothing。起初我认为使用monad可能是正确的方法,但我一直无法让任何东西正常工作。我想知道,如果有的话,正确的方法是什么


如果有帮助的话,问题的背景是我正在进行的一个项目,它为句子中的单词指定词性标签。对于我的标记集,我使用分类语法类型;这些是类型化的lambda表达式,如
(e->s)
(e->(e->s))
,其中
e
s
分别是名词和句子的类型。例如,
kill
的类型为
(e->(e->(e->s))
,它包含两个名词短语并返回一个句子。我想写一个函数,它获取此类对象的列表,并找出是否有任何方法将它们组合到
s
类型的对象。当然,这正是Haskell的类型检查器所做的,因此为每个单词指定一个适当类型的lambda表达式应该很简单,剩下的就让Haskell来做。问题是,如果无法访问
s
,Haskell的类型检查器自然会停止程序运行。

相当标准的东西。只需编写一个类型检查器,并且只在它进行类型检查时对术语进行评估<代码>评估可以执行此操作。当然,您可以丰富常量和基类型的集合;为了简单起见,我只使用了其中一种

import Control.Applicative ((<$), (<$>))
import Control.Monad (guard)
import Safe (atMay)

data Type
    = Base
    | Arrow Type Type
    deriving (Eq, Ord, Read, Show)

data Term
    = Const
    | Var Int -- deBruijn indexing; the nearest enclosing lambda binds Var 0
    | Lam Type Term
    | App Term Term
    deriving (Eq, Ord, Read, Show)

check :: [Type] -> Term -> Maybe Type
check env Const = return Base
check env (Var v) = atMay env v
check env (Lam ty tm) = Arrow ty <$> check (ty:env) tm
check env (App tm tm') = do
    Arrow i o <- check env tm
    i' <- check env tm'
    guard (i == i')
    return o

eval :: Term -> Term
eval (App tm tm') = case eval tm of
    Lam _ body -> eval (subst 0 tm' body)
eval v = v

subst :: Int -> Term -> Term -> Term
subst n tm Const = Const
subst n tm (Var m) = case compare m n of
    LT -> Var m
    EQ -> tm
    GT -> Var (m-1)
subst n tm (Lam ty body) = Lam ty (subst (n+1) tm body)
subst n tm (App tm' tm'') = App (subst n tm tm') (subst n tm tm'')

evalMay :: Term -> Maybe Term
evalMay tm = eval tm <$ check [] tm
import Control.Applicative((术语->可能类型
检查环境常数=返回基准
检查环境(Var v)=atMay环境v
检查环境(Lam ty tm)=箭头ty检查(ty:env)tm
检查环境(应用程序tm')=do
箭头i o eval(底座0 tm'阀体)
评估v=v
subst::Int->Term->Term->Term
subst n tm常数=常数
subst n tm(Var m)=案例比较m n
LT->Var m
EQ->tm
GT->Var(m-1)
subst n tm(Lam ty body)=Lam ty(subst(n+1)tm body)
subst n tm(App tm'tm')=App(subst n tm')(subst n tm“”)
evalMay::术语->可能术语

evalMay tm=eval tm我想用一种稍微不同的方法扩展@Daniel Wagner的优秀答案:不是通过类型检查返回一个有效类型(如果有),而是返回一个类型化表达式,然后保证我们可以计算它(因为简单类型的lambda演算是强规范化的)基本思想是,
check-ctx-te
返回
Just(ctx |-e::t)
iff
e
可以在某些上下文
ctx
中的
t
处键入,然后给定一些类型化表达式
ctx |-e::t
,我们可以在一些类型正确的
环境中对其进行评估

实施 我将使用单例模拟Pi类型的
check:(ctx::[type])->(a::type)->Term->Maybe(TTerm ctx a)
,这意味着我们需要打开每个GHC扩展和厨房水槽:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds, KindSignatures, TypeFamilies, TypeOperators #-}
{-# LANGUAGE TemplateHaskell #-} -- sigh...

import Data.Singletons.Prelude
import Data.Singletons.TH
import Data.Type.Equality
第一位是非类型化表示,直接来自@Daniel Wagner的答案:

data Type = Base
          | Arrow Type Type
          deriving (Show, Eq)

data Term = Const
          | Var Int
          | Lam Type Term
          | App Term Term
          deriving Show
但我们也将通过将
Base
解释为
()
箭头t1 t2
解释为
t1->t2
来给出这些类型的语义:

 type family Interp (t :: Type) where
    Interp Base = ()
    Interp (Arrow t1 t2) = Interp t1 -> Interp t2
为了与de Bruijn主题保持一致,上下文是类型列表,变量是上下文的索引。给定上下文类型的环境,我们可以查找变量索引以获得值。请注意,
lookupVar
是一个总函数

data VarIdx (ts :: [Type]) (a :: Type) where
    Here :: VarIdx (a ': ts) a
    There :: VarIdx ts a -> VarIdx (b ': ts) a

data Env (ts :: [Type]) where
    Nil :: Env '[]
    Cons :: Interp a -> Env ts -> Env (a ': ts)

lookupVar :: VarIdx ts a -> Env ts -> Interp a
lookupVar Here      (Cons x _)  = x
lookupVar (There v) (Cons _ xs) = lookupVar v xs
好的,我们已经准备好了所有的基础设施来实际编写一些代码。首先,让我们定义一个
术语的类型化表示,以及一个(total!)求值器:

data TTerm (ctx :: [Type]) (a :: Type) where
    TConst :: TTerm ctx Base
    TVar :: VarIdx ctx a -> TTerm ctx a
    TLam :: TTerm (a ': ctx) b -> TTerm ctx (Arrow a b)
    TApp :: TTerm ctx (Arrow a b) -> TTerm ctx a -> TTerm ctx b

eval :: Env ctx -> TTerm ctx a -> Interp a
eval env TConst = ()
eval env (TVar v) = lookupVar v env
eval env (TLam lam) = \x -> eval (Cons x env) lam
eval env (TApp f e) = eval env f $ eval env e
到目前为止还不错。
eval
很好,因为它的输入只能表示简单类型的lambda演算的类型良好的术语。因此@Daniel的计算器的部分工作必须在将非类型表示转换为类型表示时完成

推断
背后的基本思想是,如果类型推断成功,它只返回
项te
,其中
t
Sing
leton对
e
类型的见证

$(genSingletons [''Type])
$(singDecideInstance ''Type)

-- I wish I had sigma types...
data SomeTerm (ctx :: [Type]) where
    TheTerm :: Sing a -> TTerm ctx a -> SomeTerm ctx

data SomeVar (ctx :: [Type]) where
    TheVar :: Sing a -> VarIdx ctx a -> SomeVar ctx

-- ... and pi ones as well
infer :: Sing ctx -> Term -> Maybe (SomeTerm ctx)
infer _ Const = return $ TheTerm SBase TConst
infer ts (Var n) = do
    TheVar t v <- inferVar ts n
    return $ TheTerm t $ TVar v
infer ts (App f e) = do
    TheTerm t0 e' <- infer ts e
    TheTerm (SArrow t0' t) f' <- infer ts f
    Refl <- testEquality t0' t0
    return $ TheTerm t $ TApp f' e'
infer ts (Lam ty e) = case toSing ty of
    SomeSing t0 -> do
        TheTerm t e' <- infer (SCons t0 ts) e
        return $ TheTerm (SArrow t0 t) $ TLam e'

inferVar :: Sing ctx -> Int -> Maybe (SomeVar ctx)
inferVar (SCons t _) 0 = return $ TheVar t Here
inferVar (SCons _ ts) n = do
    TheVar t v <- inferVar ts (n-1)
    return $ TheVar t $ There v
inferVar _ _ = Nothing
示例会话 让我们在GHCi中试用我们的功能:

λ» :set -XStandaloneDeriving -XGADTs
λ» deriving instance Show (VarIdx ctx a)
λ» deriving instance Show (TTerm ctx a)

λ» let id = Lam Base (Var 0) -- \x -> x
λ» check SNil (SBase `SArrow` SBase) id
Just (TLam (TVar Here))

λ» let const = Lam Base $ Lam Base $ Var 1 -- \x y -> x
λ» check SNil (SBase `SArrow` SBase) const
Nothing -- Oops, wrong type
λ» check SNil (SBase `SArrow` (SBase `SArrow` SBase)) const
Just (TLam (TLam (TVar Here)))

λ» :t eval Nil <$> check SNil (SBase `SArrow` (SBase `SArrow` SBase)) const
eval Nil <$> check SNil (SBase `SArrow` (SBase `SArrow` SBase)) const
  :: Maybe (() -> () -> ())
-- Note that the `Maybe` there comes from `check`, not `eval`!
λ» let Just const' = check SNil (SBase `SArrow` (SBase `SArrow` SBase)) const
λ» :t eval Nil const'
eval Nil const' :: () -> () -> ()
λ» eval Nil const' () ()
()
λ»:set-XStandaloneDeriving-XGADTs
λ»导出实例显示(VarIdx ctx a)
λ»导出实例显示(TTerm ctx a)
λ»let id=Lam Base(Var 0)--\x->x
λ»检查SNil(SBase`SArrow`SBase)id
只是(TLam(这里是TVar))
λ»设常数=Lam Base$Lam Base$Var 1--\x y->x
λ»检查SNil(SBase`SArrow`SBase)常数
没什么,哎呀,打错了
λ»检查SNil(SBase`SArrow`(SBase`SArrow`SBase))常数
就是(TLam(TLam(这里是TVar))
λ»:t eval Nil check SNil(SBase`SArrow`(SBase`SArrow`SBase))常数
评估无检查SNil(SBase`SArrow`(SBase`SArrow`SBase))常数
::也许(()->()->())
--注意,这里的'Maybe'来自'check',而不是'eval'!
λ»让Just const'=检查SNil(SBase`SArrow`(SBase`SArrow`SBase))const
λ»:t eval Nil const'
求值零常数'::()->()->()
λ»评估零常数'()()
()

您能否提供一个完整的示例,说明您正在尝试执行的操作?可能是几个单词、一个进行类型检查的句子和一个不进行类型检查的句子,说明您希望将故障的运行时值而不是编译时值?如果您想知道是否“有任何方法可以将它们组合起来”要找到一个类型,你需要的搜索比Haskell的类型检查器目前所做的要多(有一个工具,它的名字中有“精灵”,但我现在找不到它的链接)。啊,是的,这个工具是。它是相关的,因为有一小组类型化对象-单位
()
,元组
(,)
,以及lambda构造函数
λ» :set -XStandaloneDeriving -XGADTs
λ» deriving instance Show (VarIdx ctx a)
λ» deriving instance Show (TTerm ctx a)

λ» let id = Lam Base (Var 0) -- \x -> x
λ» check SNil (SBase `SArrow` SBase) id
Just (TLam (TVar Here))

λ» let const = Lam Base $ Lam Base $ Var 1 -- \x y -> x
λ» check SNil (SBase `SArrow` SBase) const
Nothing -- Oops, wrong type
λ» check SNil (SBase `SArrow` (SBase `SArrow` SBase)) const
Just (TLam (TLam (TVar Here)))

λ» :t eval Nil <$> check SNil (SBase `SArrow` (SBase `SArrow` SBase)) const
eval Nil <$> check SNil (SBase `SArrow` (SBase `SArrow` SBase)) const
  :: Maybe (() -> () -> ())
-- Note that the `Maybe` there comes from `check`, not `eval`!
λ» let Just const' = check SNil (SBase `SArrow` (SBase `SArrow` SBase)) const
λ» :t eval Nil const'
eval Nil const' :: () -> () -> ()
λ» eval Nil const' () ()
()