haskell - 在 Haskell 中只允许不同的“任何”类型
问题描述
假设我们有一个带有签名的函数
foo :: a -> b -> Int
是否可以强制执行确保a和b不同的约束?那是
foo :: Int -> String -> Int -- ok
foo :: Int -> Int -> Int -- not ok
这个问题的目的是了解更多关于 Haskell 的信息,也许可以解决我面临的设计问题。如果 a == b,我的特殊情况没有意义,所以我想在编译器级别禁止这种情况。我可能可以用不同的设计完全解决这个问题,但现在不是重点——潘多拉魔盒已经打开,我想知道类型级别的等式约束是否可能。
解决方案
像这样?
{-# LANGUAGE DataKinds #-}
module TyEq where
import Data.Type.Equality (type (==))
import GHC.TypeLits
import Data.Kind (Constraint)
class ((a == b) ~ eq) => Foo a b eq where
foo :: a -> b -> Int
instance (TypeError ('Text "NAUGHTY!"), (a == b) ~ True) => Foo a b 'True where
foo _ _ = error "The types have failed us!"
instance (a == b) ~ False => Foo a b 'False where
foo _ _ = 42
--_ = foo True True -- NAUGHTY!
_ = foo () True
_ = foo True (42 :: Int)
请注意 Foo 类型类中如何eq
需要索引,或者尽管实例上下文不同(仅考虑头),但我们会收到“重复实例”错误。
我们可以使用特定目的类型族来简化这一点:
type family Check a b :: Constraint where
Check a a = TypeError ('Text "VERY NAUGHTY!")
Check a b = ()
foo' :: Check a b => a -> b -> Int
foo' _ _ = 42
--_ = foo' True True -- VERY NAUGHTY!
_ = foo' () True
_ = foo' True (42 :: Int)
我很确定我已经从 Sandy Maguire 的“Thinking with Types”中学到了这一切,我真诚地向所有感兴趣的人推荐 :)
推荐阅读
- java - 如何修复错误 404:源服务器未找到目标资源的当前表示
- java - 如何使用 apache POI 创建包含两个 CategoryAxis 的 LineChart?
- build.gradle - 如何修复模块 class.jar 中发现的此错误重复类
- javascript - 需要帮助循环一些引号
- android - Sqlite 在模拟器上运行完美,但不能在移动设备上运行
- node.js - Node js检查用户ID是否在数组中
- python - 如何在 pysnmp 中添加新的 MIB 文本文件?
- javascript - Electron.js Uncaught ReferenceError: require is not defined
- sql - 在 SQL Server 中重新编号从“1”开始的汇总部分字段
- php - 无法使用 apt-get 安装 PHP 包,给出“E: Unable to locate package”