Haskell中如何在内部函数复用父函数的类型约束与参数?
Haskell代码重构问题解答
问题1:内部函数访问外层arr参数的错误
你想让where子句里的内部函数直接使用外层的arr参数,这个思路是对的——Haskell的where子句确实可以访问外层作用域的变量,但你的修改犯了两个错误:
- 调用
findLargestIndexOfElement时多传了arr参数,你已经把它的类型签名改成了sourceElementType -> sourceIndexType,它不需要再接收数组参数,直接用外层的arr即可。 - 原调用逻辑里,
findLargestElement已经是一个具体值(sourceElementType类型),不需要额外传递arr给它。
修正后的代码:
maxIndex :: (Ix sourceIndexType, Ord sourceElementType) => Array sourceIndexType sourceElementType -> sourceIndexType maxIndex arr = findLargestIndexOfElement findLargestElement where findLargestElement :: sourceElementType findLargestElement = maximum $ elems arr findLargestIndexOfElement :: sourceElementType -> sourceIndexType findLargestIndexOfElement element = fst $ foldr1 (\(itemk,itemv) (acck, accv) -> if element==itemv then (itemk,itemv) else (acck,accv)) (assocs arr)
问题2:复用外层类型约束的错误
你去掉内部函数的类型约束后报错,是因为Haskell默认会把where子句里的类型变量当成全新的多态变量,不会和外层函数的类型变量绑定。要解决这个问题,需要启用ScopedTypeVariables扩展,它能让内部函数的类型变量和外层函数的同名变量共享上下文。
启用扩展后,在外层函数的类型签名里用forall显式声明类型变量(GHC 8.0+可省略,但显式声明更清晰),内部函数就能复用外层的类型约束了。
修正后的代码:
{-# LANGUAGE ScopedTypeVariables #-} maxIndex :: forall sourceIndexType sourceElementType. (Ix sourceIndexType, Ord sourceElementType) => Array sourceIndexType sourceElementType -> sourceIndexType maxIndex arr = findLargestIndexOfElement arr (findLargestElement arr) where findLargestElement :: Array sourceIndexType sourceElementType -> sourceElementType findLargestElement arr = maximum $ elems arr findLargestIndexOfElement :: Array sourceIndexType sourceElementType -> sourceElementType -> sourceIndexType findLargestIndexOfElement arr element = fst $ foldr1 (\(itemk,itemv) (acck, accv) -> if element==itemv then (itemk,itemv) else (acck,accv)) (assocs arr)
内容的提问来源于stack exchange,提问作者Richard
相关产品推荐
相关产品推荐

