haskell - foldMap 回调中强制的意外行为
问题描述
此代码编译:
import Data.List (isPrefixOf)
import Data.Monoid (Any(..))
import Data.Coerce
isRoot :: String -> Bool
isRoot path = getAny $ foldMap (coerce . isPrefixOf) ["src", "lib"] $ path
我coerce
用作包装 in 最终结果的快捷isPrefixOf
方式Any
。
这个类似的代码无法编译(注意缺少.
):
isRoot :: String -> Bool
isRoot path = getAny $ foldMap (coerce isPrefixOf) ["src", "lib"] $ path
错误是:
* Couldn't match representation of type `a0' with that of `Char'
arising from a use of `coerce'
* In the first argument of `foldMap', namely `(coerce isPrefixOf)'
In the first argument of `($)', namely
`foldMap (coerce isPrefixOf) ["src", "lib"]'
In the second argument of `($)', namely
`foldMap (coerce isPrefixOf) ["src", "lib"] $ path'
但我的直觉是它也应该编译。毕竟,我们知道isPrefixOf
will 的参数是String
s,并且结果必须是类型Any
。没有歧义。所以String -> String -> Bool
应该转换为String -> String -> Any
. 为什么它不起作用?
解决方案
这与强制无关。这只是一般的约束解决。考虑:
class Foo a b
instance Foo (String -> Bool) (String -> Any)
instance Foo (String -> String -> Bool) (String -> String -> Any)
foo :: Foo a b => a -> b
foo = undefined
bar :: String -> String -> Any
bar = foo . isPrefixOf
baz :: String -> String -> Any
baz = foo isPrefixOf
工作正常的定义bar
;baz
失败的定义。
在bar
中, 的类型isPrefixOf
可以直接推断为,只需将s 的第一个参数(即)的类型与 的第一个参数类型String -> String -> Bool
统一即可。bar
String
isPrefixOf
在中,无法从表达式baz
中推断出 的类型。该函数可以对 的类型做任何事情来获得结果类型。isPrefixOf
foo isPrefixOf
foo
isPrefix
String -> String -> Any
请记住,约束并不会真正影响类型统一。统一就像没有约束一样发生,当统一完成时,需要约束。
回到你原来的例子,以下是一个完全有效的强制,所以歧义是真实的:
{-# LANGUAGE TypeApplications #-}
import Data.Char
import Data.List (isPrefixOf)
import Data.Monoid (Any(..))
import Data.Coerce
newtype CaselessChar = CaselessChar Char
instance Eq CaselessChar where CaselessChar x == CaselessChar y = toUpper x == toUpper y
isRoot :: String -> Bool
isRoot path = getAny $ foldMap (coerce (isPrefixOf @CaselessChar)) ["src", "lib"] $ path
推荐阅读
- amazon-web-services - 创建状态存储桶时,远程后端 S3 的 Terraform 初始化失败
- reactjs - 如何在 React Application for Adobe 分析(adobe 启动)中实现数据层?
- android - 如何在颤振中改变芯片的形状
- debugging - 尾随反斜杠错误 Web 模式内容类型
- java - 运行独立 jar 时出现 JAVA javax.net.ssl.SSLHandshakeException 错误
- amazon-web-services - EC2 自动扩展的 Amazon Elasticsearch 访问策略
- mysql - MySQL从第一列中选择第二列中具有特定值的所有值
- node.js - AWS Elastic BeanStalk nodejs 部署错误
- algorithm - 错误:没有匹配的函数调用“交换”
- arrays - 如何在顶级数组上应用“arrayFilters”?