haskell 是否可以在函数类型上进行模式匹配?

6za6bjd0  于 2023-08-06  发布在  其他
关注(0)|答案(3)|浏览(131)

我正在写一个迷你语言,我遇到了一个情况,我试图处理一个抽象的语法树,这样它要么返回一个异常,要么返回一个将解析为bool的函数。下面是一个简单的例子:

data MyException = Can'tResolveToBool

data InputToBeAddedLater =
    InputToBeAddedLater String

data Exp a =
    ReturnsBoolFunc String (Exp a)
    | IsBool Bool
    | ReturnsExpFunc String (Exp a)

resolveToExp :: String -> Exp a -> (InputToBeAddedLater -> Exp a)
resolveToExp funcName arg
    | funcName == "patently_false" = (\_ -> IsBool False)

resolveToBool :: Exp a -> Either MyException Bool
resolveToBool (ReturnsBoolFunc funcName (ReturnsExpFunc fn arg)) =
    let resolved = resolveToExp fn arg
    in case resolved of
        ((InputToBeAddedLater _) -> (IsBool bool)) -> Right bool
        ((InputToBeAddedLater _) -> (ReturnsExpFunc _ _)) -> Left Can'tResolveToBool

字符串
最后一行是我(可悲的是,非功能性的)尝试在函数类型上进行模式匹配。GHC建议我尝试ViewPatterns扩展,但简单地看一下,我不确定这是我需要的。在概念上是不可能做到我在这里尝试做的事情吗?
谢谢你,谢谢

bn31dyow

bn31dyow1#

让我们戏剧性地简化这个问题。这是你问题的核心:我可以实现desired吗?

desired :: (String -> Bool) -> Bool
desired f = case f of
    (_ -> True ) -> True
    (_ -> False) -> False

字符串
希望所有的谷壳都被筛掉,很明显,这是不可能做到的:关于f是否返回TrueFalse,不一定存在事实。它返回的值可以取决于你传递给它的输入!

j2cgzkjk

j2cgzkjk2#

据我所知,你想用这种模式表达什么

case resolved of
    ((InputToBeAddedLater _) -> (IsBool bool)) -> ...

字符串
是检查resolved是否返回 * 任何输入 * 与外部构造函数IsBool的东西。即是否为

resolved (InputToBeAddedLater i) = IsBool (...)


由于非严格性,您至少可以 * 验证 *,而无需提供具体的i

case resolved (InputToBeAddedLater undefined) of
    (IsBool bool) -> Right bool
    (ReturnsExpFunc _ _) -> Left Can'tResolveToBool


这样做的问题是,如果resolved在提供外部构造函数之前实际计算了它的参数,那么它就会崩溃,例如

resolved (InputToBeAddedLater "") = IsBool False
resolved (InputToBeAddedLater s) = ReturnsExpFunc "" (IsBool True)


您现在可以在此基础上添加一些错误捕获机制,但这只能在IO中完成,而且无论如何都是很麻烦的。
实际上,我认为这是一个XY问题,实际上应该做的是给予resolved一种方法,在没有任何输入的情况下通知其结果的外部构造函数。这可以通过泛化Exp来实现,因此它 * 包含 * InputToBeAddedLater,但只有在揭示最外面的构造函数之后:

data ExpH m a
  = ReturnsBoolFunc (m (String, Exp a))
  | IsBool (m Bool)
  | ReturnsExpFunc (m (String, Exp a))

type Exp = ExpH Identity

resolveToExp :: String -> Exp a -> ExpH ((->) InputToBeAddedLater) a
resolveToExp funcName arg
    | funcName == "patently_false" = IsBool (const False)

resolveToBool :: Exp a -> Either MyException Bool
resolveToBool (ReturnsBoolFunc funcName (Identity (ReturnsExpFunc fn arg)))
   = case resolveToExp fn arg of
        IsBool b -> Right (b undefined) -- here you would actually provide an argument
        ReturnsExpFunc _ -> Left Can'tResolveToBool

bf1o4zei

bf1o4zei3#

作为一般的答案,可以在一些函数上进行模式匹配,像(Tag ->)这样的可表示函子同构于Vector 3

type Tag :: Type
data Tag = FirstNameTag | LastNameTag | AddressTag

type Person :: Type
type Person = Tag -> String

personToTuple :: Person -> (String, String, String)
personToTuple person = (person FirstNameTag, person LastNameTag, person AddressTag)

pattern FirstName :: String -> Person
pattern FirstName firstName <- (personToTuple -> (firstName, _, _))

pattern LastName :: String -> Person
pattern LastName lastName <- (personToTuple -> (_, lastName, _))

pattern Address :: String -> Person
pattern Address address <- (personToTuple -> (_, _, address))

字符串

相关问题