Algorithm 与Haskell行为不一致

Algorithm 与Haskell行为不一致,algorithm,haskell,perceptron,Algorithm,Haskell,Perceptron,我在读感知器,并试图在haskell中实现一个。就我所能测试的而言,该算法似乎正在运行。我打算在某个时候完全重写代码,但在重写之前,我想问一些arosen在编写代码时遇到的问题 当返回完整的神经元时,可以训练神经元let neuron=train set[1,1]起作用,但如果我更改train函数以返回不带输入的不完整神经元,或尝试模式匹配并仅创建不完整神经元,则代码将落入无持续循环 tl;当返回完整的神经元时,一切正常,但当返回可恢复的神经元时,代码陷入循环 module Main where

我在读感知器,并试图在haskell中实现一个。就我所能测试的而言,该算法似乎正在运行。我打算在某个时候完全重写代码,但在重写之前,我想问一些arosen在编写代码时遇到的问题

当返回完整的神经元时,可以训练神经元
let neuron=train set[1,1]
起作用,但如果我更改train函数以返回不带输入的不完整神经元,或尝试模式匹配并仅创建不完整神经元,则代码将落入无持续循环

tl;当返回完整的神经元时,一切正常,但当返回可恢复的神经元时,代码陷入循环

module Main where
import System.Random
type Inputs = [Float]
type Weights = [Float]
type Threshold = Float
type Output = Float
type Trainingset = [(Inputs, Output)]

data Neuron = Neuron Threshold Weights Inputs deriving Show

output :: Neuron -> Output
output (Neuron threshold weights inputs) = 
          if total >= threshold then 1 else 0
          where total = sum $ zipWith (*) weights inputs

rate :: Float -> Float -> Float
rate t o = 0.1 * (t - o)

newweight :: Float -> Float -> Weights -> Inputs -> Weights
newweight t o weight input = zipWith nw weight input
  where nw w x = w + (rate t o) * x

learn :: Neuron -> Float -> Neuron
learn on@(Neuron tr w i) t = 
  let o = output on
  in Neuron tr (newweight t o w i) i

converged :: (Inputs -> Neuron) -> Trainingset -> Bool
converged n set = not $ any (\(i,o) -> output (n i) /= o) set

train :: Weights -> Trainingset -> Neuron
train w s = train' s (Neuron 1 w)

train' :: Trainingset -> (Inputs -> Neuron) -> Neuron
train' s n | not $ converged n set 
              = let (Neuron t w i) = train'' s n
                in train' s (Neuron t w)
          | otherwise = n $ fst $ head s

train'' :: Trainingset -> (Inputs -> Neuron) -> Neuron
train'' ((a,b):[]) n = learn (n a) b
train'' ((a,b):xs) n = let 
                        (Neuron t w i) = learn (n a) b
                      in
                        train'' xs (Neuron t w)

set :: Trainingset
set = [
        ([1,0], 0),
        ([1,1], 1),
        ([0,1], 0),
        ([0,0], 0)
      ]

randomWeights :: Int -> IO [Float]
randomWeights n = 
  do
    g <- newStdGen
    return $ take n $ randomRs (-1, 1) g

main = do
  w <- randomWeights 2
  let (Neuron t w i) = train w set
  print $ output $ (Neuron t w [1,1])
  return ()
modulemain其中
导入系统。随机
类型输入=[Float]
类型权重=[Float]
类型阈值=浮动
类型输出=浮点
类型培训集=[(输入、输出)]
数据神经元=神经元阈值权重输入导出显示
输出::神经元->输出
输出(神经元阈值权重输入)=
如果总数>=阈值,则为1,否则为0
其中total=带(*)权重输入的$zipWith总和
费率:浮动->浮动->浮动
比率TO=0.1*(t-o)
newweight::Float->Float->Weights->Inputs->Weights
新重量t o重量输入=带nw重量输入的ZIP
式中,nw w x=w+(速率t o)*x
学习::神经元->浮点->神经元
学习@(神经元trw i)t=
设o=输出开启
在神经元tr(newweight t to w i)i中
聚合::(输入->神经元)->训练集->布尔
聚合n集=非$any(\(i,o)->输出(ni)/=o)集
训练:重量->训练集->神经元
序列w s=序列s(神经元1 w)
训练::训练集->(输入->神经元)->神经元
列车的n |不是$Converge n集合
=let(神经元twi)=序列n
列车内(神经元t w)
|否则=n$fst$head s
序列“”::Trainingset->(输入->神经元)->神经元
列车“”((a,b):[])n=学习(n a)b
列“”((a,b):xs)n=let
(神经元twi)=学习(na)b
在里面
列车“”xs(神经元t w)
集合::训练集合
集合=[
([1,0], 0),
([1,1], 1),
([0,1], 0),
([0,0], 0)
]
随机权重::Int->IO[Float]
随机权重n=
做

g也许我遗漏了什么,但我将您的测试用例归结为以下程序:

module Main where
data Foo a = Foo a

main = do
  x ← getLine
  let (Foo x) = Foo x
  putStrLn x
这进一步简化为:

main = do
  x ← getLine
  let x = x
  putStrLn x
问题在于将
(foox)
绑定到依赖于x的东西 是一个循环依赖项。要计算x,我们需要知道x的值 十,。好的,我们只需要计算x。要计算x,我们需要 知道x的值。好的,我们只计算x。等等

这不是C,记住:它是绑定,不是赋值,还有绑定 评估是懒惰的

使用更好的变量名,这一切都会起作用:

module Main where
data Foo a = Foo a

main = do
  line ← getLine
  let (Foo x) = Foo line
  putStrLn x

(在您的例子中,所讨论的变量是
w

也许我遗漏了什么,但我将您的测试用例归结为以下程序:

module Main where
data Foo a = Foo a

main = do
  x ← getLine
  let (Foo x) = Foo x
  putStrLn x
这进一步简化为:

main = do
  x ← getLine
  let x = x
  putStrLn x
问题在于将
(foox)
绑定到依赖于x的东西 是一个循环依赖项。要计算x,我们需要知道x的值 十,。好的,我们只需要计算x。要计算x,我们需要 知道x的值。好的,我们只计算x。等等

这不是C,记住:它是绑定,不是赋值,还有绑定 是懒惰的评估

使用更好的变量名,这一切都会起作用:

module Main where
data Foo a = Foo a

main = do
  line ← getLine
  let (Foo x) = Foo line
  putStrLn x

(在您的例子中,所讨论的变量是
w

这是Haskell中的一个常见错误。你不能这样说:

let x = 0
let x = x + 1

它的意思和赋值语言中的意思一样,甚至是非递归绑定。第一行是不相关的,它被第二行所遮蔽,第二行将
x
定义为
x+1
,也就是说,它递归地定义
x=(((…)+1)+1)+1
,这将在求值时循环。

这是Haskell的一个常见错误。你不能这样说:

let x = 0
let x = x + 1

它的意思和赋值语言中的意思一样,甚至是非递归绑定。第一行是不相关的,它被第二行所遮蔽,第二行将
x
定义为
x+1
,也就是说,它递归地定义
x=((((…)+1)+1)+1
,这将在计算时循环。

1)在什么情况下,“当我进行更改时无限循环”是一种“不一致的行为”?2) 如果你这样做的话,你是否可以减少(或至少评论)你的例子来隔离让你困惑的一小部分,人们更可能做出回应,并在回应中正确地解决你的困惑。展示实现你期望的代码会很方便,以及做了你不期望的事情的改变。这个问题不是用w来重新约束w吗?“let a=a;print a”总是一个无限循环。1)在什么情况下,“当我进行更改时无限循环”是一个“不一致的行为”?2) 如果你这样做的话,你是否可以减少(或至少评论)你的例子来隔离让你困惑的一小部分,人们更可能做出回应,并在回应中正确地解决你的困惑。展示实现你期望的代码会很方便,以及做了你不期望的事情的改变。这个问题不是用w来重新约束w吗?“let a=a;print a”总是一个无限循环。