我有以下数据类型
type Store = Loc -> Z
type Loc = Z
type Z = Integer
其中的基本思想是商店将Location映射到一个整数。每个位置都由其自己的整数标识符表示。
现在,在任务的其他地方,我有一个Store(Loc->Z),我需要从中提取整数。所以我需要一个函数,它接收一个存储并只返回Z部分。
funExtract :: Store -> Z
funExtract sto = ???
就我的一生而言,我所尝试的一切都会带来某种错误。如有任何帮助,我们将不胜感激。感谢
是的,通过构建函数来模仿商店。这是编程语言类中常见的一个很好的练习。您将需要两个函数,一个用于构建存储,另一个用于提取值。要构建一个存储,您需要原始存储、要插入的元素和位置:
type Store = Loc -> Z
type Loc = Z
type Z = Integer
extend :: Loc -> Z -> Store -> Store
extend loc val st = look ->
if look == loc then val else st look
在extend
中,我们只定义了一个函数,如果您将值传递给匹配的位置,该函数将返回值。如果位置不匹配,那么位置可能是在原始存储中定义的,所以我们将该存储应用于查找。
现在要实现查找:
funExtract :: Store -> Loc -> Z
funExtract sto loc = sto loc
注意到了吗?您提出的是将存储系统实现为一个函数,因此查找只是函数应用程序。由于我们不会返回具有empty
值的东西,如Maybe a
类型,因此如果位置不在我们的商店中,我们将需要采取严厉措施。让我们在空商店上查找一个错误:
emptyStore :: Store
emptyStore loc = error $ "Can not find location " ++ show loc ++ "."
下面我在GHCi中玩了一点这个结构。
*Main> let sto = extend 1 31337 (extend 0 1337 emptyStore)
*Main> sto 0
1337
*Main> sto 1
31337
*Main> sto 2
*** Exception: Can not find location 2.
Store
是一种函数类型,它获取一个位置并将其映射到一个整数。要实现任务,您应该将所有位置存储在funExtract
中,或者使用像Data.Map
这样的外部存储。以下是如何做到这一点。
import qualified Data.Map as DM
type Store = Loc -> Z
type Loc = Z
type Z = Integer
-- First way --
funExtract :: Store
funExtract 1 = 2
funExtract 2 = 9
-- here could be more values: --
-- for each new values a new pattern --
funExtract 108 = 17
{- This solution doesn't allow to add new locations
at the runtime. Look at Thomas's answer to understand
how to do this with function as a container. Or look
at the second way: -}
-- Second way --
-- To add new location, add it to locStorage using
-- functions from Data.Map.
locStorage :: DM.Map Loc Z
locStorage = DM.fromList [(1, 2), (2, 9), {- ... -} (108, 17)]
-- `funExtract` becomes just a query
funExtract' :: Store
funExtract' = (DM.!) locStorage