haskell学习总结(三)::正则表达式
haskell中的正则表达式用法[1]
-- 导入正则模块
Prelude>:module +Text.Regex.Posix
-- 全部的正则操作基本都使用(=~)这一个函数操作
Prelude Text.Regex.Posix>:t (=~)
(=~)
:: (RegexContext Regex source1 target,
RegexMaker Regex CompOption ExecOption source) =>
source1 -> source -> target
-- 可见 (=~)的类型是非常复杂的,
-- 但是我们使用起来确实非常方便,
-- 类似OO语言中的方法重载(根据返回值类型进行重载)
-- 显示指明返回值是Bool类型
Prelude Text.Regex.Posix>"hello world" =~ "hello" :: Bool
--返回True,说明"hello world" 匹配了正则"hello"
True
-- 显示的指明返回值是Int类型
Prelude Text.Regex.Posix>"hello world" =~ "l" :: Int
-- "l"在"hello world"中匹配到了3次
3
通过上面简单的例子,可以看出对于不同类型的返回值,(=~)方法会进行不同的操作,返回对应类型的值,把复杂的操作都封装在模块内, 对外仅仅暴露一个简单的(=~)方法,这样的设计哲学值得学习!
关于(=~)更复杂的用法可以参考下面参考资料里的链接[1],这里就不再赘述了,其实写这篇文章的目的是想探讨一下(=~)内部到底做了什么,能够实现根据不同类型返回进行不同操作的。
个人感觉(没有读Text.Regex.Posix的源码,有时间是应该读一读的~)应该就是实现一个方法对RegexContext这个typeclass的不同实例进行封装,我自己模拟一个这样的方法来实现类似的功能:
-- Context.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
module Context where
-- MultiParamTypeClasses扩展允许我们
-- 定义一个含有两个类型变量的typeclass
class Context source target where
ret::source->target
-- FlexibleInstances扩展允许我们
-- 将String作为类型参数
instance Context String Bool where
ret str = case str of
"yes" -> True
otherwise -> False
instance Context String Int where
ret str = case str of
"one" -> 1
otherwise -> 0
instance Context String String where
ret s = s
instance Context Int Int where
ret = (+) 1
instance Context Bool Bool where
ret b = not b
instance Context Int Bool where
ret i = case i of
1 -> True
otherwise -> False
instance Context Int String where
ret i = (++) "Num:" (show i)
-- emit方法就会根据返回值和参数的类型调用不同的Cotext的实例的ret方法
emit::(Context source target) => source->target
emit = ret
使用我们emit方法:
Prelude>:load Context.hs
*Contex>emit True::Bool
False
*Context>emit (1::Int)::Bool
True
*Context>emit "hello"::String
"hello"
*Context>emit "yes"::Bool
True
这只是我猜测的实现,真正的实现不一定是这样,或者比这个复杂的多的多。。。
关于FlexibleInstances扩展请见stack overflow第二个回答
参考资料
haskell学习总结