gpt4 book ai didi

Haskell:将某些函数应用于嵌套 2 元组的函数

转载 作者:行者123 更新时间:2023-12-04 22:30:04 24 4
gpt4 key购买 nike

假设我有一个像 ('a',(1,("Hello",False)) 的元组。只是为了好玩(阅读:学习),我想创建一个函数,将正确形式的某些函数应用于任何此类元组并返回结果。用法示例:

applyFnToTuple ('o',('t','w')) $ \a b c -> [a,b,c] == "otw"
applyFnToTuple ('h','i') $ \a b -> [a,b] == "hi"
applyFnToTuple ("hello",('y','o')) $ \a b c -> a ++ [b,c]

我已经按照以下方式完成了大部分工作:
type family TupleFn ty out where
TupleFn (a,b) output = a -> (TupleFn b output)
TupleFn b output = b -> output

class ApplyFnToTuple a where
applyFnToTuple :: a -> TupleFn a out -> out

instance ApplyFnToTuple b => ApplyFnToTuple (a,b) where
applyFnToTuple (a,b) fn = applyFnToTuple b (fn a)

instance ApplyFnToTuple a where
applyFnToTuple b fn = fn b

症结在于最后一个实例。我完全希望需要添加 {-# OVERLAPPABLE #-} 因为 a(a,b) 更通用。我也很难确切地了解 GHC 如何解析 a 和我的 TupleFn 类的正确版本并知道正确的类型 sig,但我可以很容易地将其归结为我自己缺乏理解。但无论如何,GHCI 给我的实际错误是:
Couldn't match expected type ‘a -> out’
with actual type ‘TupleFn a out’
Relevant bindings include
fn :: TupleFn a out (bound at examples.hs:574:22)
b :: a (bound at examples.hs:574:20)
applyFnToTuple :: a -> TupleFn a out -> out
(bound at examples.hs:574:5)
The function ‘fn’ is applied to one argument,
but its type ‘TupleFn a out’ has none
In the expression: fn b
In an equation for ‘applyFnToTuple’: applyFnToTuple b fn = fn b
Failed, modules loaded: none.

据我所知,我的 TupleFn 没有任何版本返回没有参数的东西,所以我真的不明白这个错误。但是,我发现只需将最后一个实例更改为更具体的内容即可进行编译,例如:
instance ApplyFnToTuple Char where
applyFnToTuple b fn = fn b

但这意味着我必须定义许多类似的实例等,这是不可取的。

我想知道的是,是否有一种相对简单的方法可以使更通用的版本工作,以及为什么会出现此特定错误?

谢谢 :)

PS:我正在运行 GHC 7.10.1

最佳答案

问题在于,在 instance ApplyFnToTuple a 的定义中,无法访问 a 不是元组的信息 - 我猜 GHC 在决定它作为定义是否正确时没有考虑如何选择实例。这意味着它无法知道 TupleFn 给出了正确的使用结果,因此实例不会进行类型检查。

为了解决这个问题,你可以添加一个等式约束来告诉它 TupleFn 是正确的。不幸的是,由于约束必须提及 out 类型,因此需要将其作为额外的类型参数包含在类中。至少,以下似乎有效(仅使用 GHC 7.8 测试):

{-# LANGUAGE TypeFamilies, FlexibleInstances,
MultiParamTypeClasses,
OverlappingInstances #-}

type family TupleFn ty out where
TupleFn (a,b) output = a -> (TupleFn b output)
TupleFn b output = b -> output

class ApplyFnToTuple a out where
applyFnToTuple :: a -> TupleFn a out -> out

instance ApplyFnToTuple b out => ApplyFnToTuple (a,b) out where
applyFnToTuple (a,b) fn = applyFnToTuple b (fn a)

instance TupleFn a out ~ (a -> out) => ApplyFnToTuple a out where
applyFnToTuple b fn = fn b

关于Haskell:将某些函数应用于嵌套 2 元组的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31548436/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com